All what you never wanted to know about sigaction(), struct sigaction, and sigset_t. Before vda started messing with sigset_t, struct sigaction and sigaction() functions, things looked this way: Structures MIPS: Ignoring bogus "#if defined(__mips__) ..." block in libc/sysdeps/linux/common/bits/kernel_sigaction.h and using libc/sysdeps/linux/mips/bits/kernel_sigaction.h as an authoritative source: HAVE_SA_RESTORER is #defined struct old_kernel_sigaction { unsigned sa_flags; sighandler_t k_sa_handler; unsigned long sa_mask; unsigned pad0[3]; /* reserved, keep size constant */ /* Abi says here follows reserved int[2] */ void (*sa_restorer)(void); #if (_MIPS_SZPTR < 64) /* For 32 bit code we have to pad struct sigaction to get * constant size for the ABI */ int pad1[1]; /* reserved */ #endif }; struct kernel_sigaction { unsigned int sa_flags; sighandler_t k_sa_handler; kernel_sigset_t sa_mask; void (*sa_restorer)(void); int s_resv[1]; /* reserved */ }; struct sigaction { unsigned sa_flags; sighandler_t sa_handler; sigset_t sa_mask; /* The ABI says here are two unused ints following. */ /* Restore handler. */ void (*sa_restorer)(void); #if _MIPS_SZPTR < 64 int sa_resv[1]; #endif }; IA64: Has no old_sigaction. What a relief. struct kernel_sigaction { sighandler_t k_sa_handler; unsigned long sa_flags; sigset_t sa_mask; }; struct sigaction { sighandler_t sa_handler; unsigned long sa_flags; sigset_t sa_mask; }; Alpha: struct old_kernel_sigaction { sighandler_t k_sa_handler; unsigned long sa_mask; unsigned sa_flags; }; struct kernel_sigaction { sighandler_t k_sa_handler; unsigned sa_flags; sigset_t sa_mask; }; struct sigaction { sighandler_t sa_handler; sigset_t sa_mask; unsigned sa_flags; }; HPPA: struct kernel_sigaction { sighandler_t k_sa_handler; unsigned long sa_flags; sigset_t sa_mask; }; struct sigaction { sighandler_t sa_handler; unsigned long sa_flags; sigset_t sa_mask; }; The rest, kernel side: HAVE_SA_RESTORER #defined struct old_kernel_sigaction { sighandler_t k_sa_handler; unsigned long sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); }; struct kernel_sigaction { sighandler_t k_sa_handler; unsigned long sa_flags; void (*sa_restorer)(void); sigset_t sa_mask; }; On userspace side, Sparc has special struct sigaction: struct sigaction { sighandler_t sa_handler; sigset_t sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); /* Not used by Linux/Sparc */ }; And finally the rest has: struct sigaction { sighandler_t sa_handler; sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }; Userspace sigset_t was uniformly defined as vector of longs big enough to hold 1024 (!) bits - carried over from glibc. Since the only arch whose struct kernel_sigaction contains sa_mask not as a last member is MIPS, MIPS has special kernel_sigset_t, which is an array of longs long enough for 128 bits. Other arches still used userspace sigset_t in struct kernel_sigaction, but it did not really matter because overlong kernel_sigaction does not hurt in sigaction() [explained below]. On kernel side, all arches define _NSIG to 65 (meaning there are 64 signals, 1..64) except MIPS, which define it to 129. Functions sigaction() [libc function] usually has two kernel_sigaction's on stack and copy (userspace) struct sigaction members into first one, executes syscall, then pulls out the result from second one. This accomodates differences in layouts of structs. The only typically present quirk is what to do with sa_restorer. libc/sysdeps/linux/arm/sigaction.c if HAVE_SA_RESTORER and (sa_flags & SA_RESTORER) is not set, sets sa_restorer to (flags & SA_SIGINFO) ? __default_rt_sa_restorer : __default_sa_restorer, and sets SA_RESTORER, otherwise passes it as-is. Which is kinda strange, because AFAICS HAVE_SA_RESTORER is *not* defined for ARM. libc/sysdeps/linux/i386/sigaction.c Forcibly sets SA_RESTORER and sa_restorer: kact.sa_flags = act->sa_flags | SA_RESTORER; kact.sa_restorer = ((act->sa_flags & SA_SIGINFO) ? &restore_rt : &restore); libc/sysdeps/linux/x86_64/sigaction.c Forcibly sets SA_RESTORER and sa_restorer: kact.sa_flags = act->sa_flags | SA_RESTORER; kact.sa_restorer = &restore_rt; libc/sysdeps/linux/mips/sigaction.c # ifdef HAVE_SA_RESTORER # if _MIPS_SIM == _ABIO32 kact.sa_restorer = act->sa_restorer; # else kact.sa_restorer = &restore_rt; # endif # endif No confusion here, HAVE_SA_RESTORER is #defined for MIPS libc/sysdeps/linux/avr32/sigaction.c if (kact.sa_flags & SA_RESTORER) { kact.sa_restorer = act->sa_restorer; } else { kact.sa_restorer = __default_rt_sa_restorer; kact.sa_flags |= SA_RESTORER; } Does not check HAVE_SA_RESTORER, but avr32 falls in "completely ordinary" category on both kernel and userspace sides, and those have it defined. libc/sysdeps/linux/xtensa/sigaction.c if (kact.sa_flags & SA_RESTORER) { kact.sa_restorer = act->sa_restorer; } else { kact.sa_restorer = __default_sa_restorer; kact.sa_flags |= SA_RESTORER; } Thus, similar to avr32. libc/signal/sigaction.c (i.e. the all other arches) # ifdef HAVE_SA_RESTORER kact.sa_restorer = act->sa_restorer; # endif Plain translation, just sa_restorer copy is protected by HAVE_SA_RESTORER #define check. Looks like here HAVE_SA_RESTORER will be undef'ed only for IA64, Alpha an HPPA. Proposed overhaul past 0.9.30 Since we can define libc-side structures at will: make sigset_t and struct sigaction identical on kernel side and libc side within each arch. If arches do not need special handling of sa_restorer, then sigaction() can directly use passed struct sigaction as-is. Otherwise, a copy is still needed, although sigaction() might have just one struct kernel_sigaction on stack and use it both for passing data to kernel and for receiving it back. Might save a few bytes. To this effect: * Make sigset_t size match kernel side on all arches. This is easy since all arches have 64 signals and only MIPS has 128. * Modify libc/sysdeps/linux/$ARCH/bits/sigaction.h so that its struct sigaction matches kernel's. If sa_restorer field is present in libc but is missing in kernel_sigaction, add it at the bottom in order to not mess up kernel_sigaction layout. * Modify libc/sysdeps/linux/$ARCH/sigaction.c to implement the logic above. In "common" pseudo-arch (libc/signal/sigaction.c file), we would not even need to do any copying, as described above. * Document discovered arch quirks while debugging this mess. * struct old_kernel_sigaction can't be disposed of in a similar way, we need to have userspace struct sigaction unchanged regardless whether we use "old" or "new" kernel sigaction() syscall. It's moot anyway because "old" one is long unused, it's from pre-2.2 kernels.