| 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. |