summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/sigaction.txt245
1 files changed, 245 insertions, 0 deletions
diff --git a/docs/sigaction.txt b/docs/sigaction.txt
new file mode 100644
index 000000000..b380e725b
--- /dev/null
+++ b/docs/sigaction.txt
@@ -0,0 +1,245 @@
+ 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.
+
+* Deal with old_kernel_sigaction later.