lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | All what you never wanted to know about sigaction(), |
| 2 | struct sigaction, and sigset_t. |
| 3 | |
| 4 | |
| 5 | Before vda started messing with sigset_t, struct sigaction |
| 6 | and sigaction() functions, things looked this way: |
| 7 | |
| 8 | |
| 9 | Structures |
| 10 | |
| 11 | MIPS: |
| 12 | |
| 13 | Ignoring bogus "#if defined(__mips__) ..." block in |
| 14 | libc/sysdeps/linux/common/bits/kernel_sigaction.h |
| 15 | and using |
| 16 | libc/sysdeps/linux/mips/bits/kernel_sigaction.h |
| 17 | as an authoritative source: |
| 18 | |
| 19 | HAVE_SA_RESTORER is #defined |
| 20 | struct old_kernel_sigaction { |
| 21 | unsigned sa_flags; |
| 22 | sighandler_t k_sa_handler; |
| 23 | unsigned long sa_mask; |
| 24 | unsigned pad0[3]; /* reserved, keep size constant */ |
| 25 | /* Abi says here follows reserved int[2] */ |
| 26 | void (*sa_restorer)(void); |
| 27 | #if (_MIPS_SZPTR < 64) |
| 28 | /* For 32 bit code we have to pad struct sigaction to get |
| 29 | * constant size for the ABI */ |
| 30 | int pad1[1]; /* reserved */ |
| 31 | #endif |
| 32 | }; |
| 33 | struct kernel_sigaction { |
| 34 | unsigned int sa_flags; |
| 35 | sighandler_t k_sa_handler; |
| 36 | kernel_sigset_t sa_mask; |
| 37 | void (*sa_restorer)(void); |
| 38 | int s_resv[1]; /* reserved */ |
| 39 | }; |
| 40 | struct sigaction { |
| 41 | unsigned sa_flags; |
| 42 | sighandler_t sa_handler; |
| 43 | sigset_t sa_mask; |
| 44 | /* The ABI says here are two unused ints following. */ |
| 45 | /* Restore handler. */ |
| 46 | void (*sa_restorer)(void); |
| 47 | #if _MIPS_SZPTR < 64 |
| 48 | int sa_resv[1]; |
| 49 | #endif |
| 50 | }; |
| 51 | |
| 52 | IA64: |
| 53 | |
| 54 | Has no old_sigaction. What a relief. |
| 55 | |
| 56 | struct kernel_sigaction { |
| 57 | sighandler_t k_sa_handler; |
| 58 | unsigned long sa_flags; |
| 59 | sigset_t sa_mask; |
| 60 | }; |
| 61 | struct sigaction { |
| 62 | sighandler_t sa_handler; |
| 63 | unsigned long sa_flags; |
| 64 | sigset_t sa_mask; |
| 65 | }; |
| 66 | |
| 67 | Alpha: |
| 68 | |
| 69 | struct old_kernel_sigaction { |
| 70 | sighandler_t k_sa_handler; |
| 71 | unsigned long sa_mask; |
| 72 | unsigned sa_flags; |
| 73 | }; |
| 74 | struct kernel_sigaction { |
| 75 | sighandler_t k_sa_handler; |
| 76 | unsigned sa_flags; |
| 77 | sigset_t sa_mask; |
| 78 | }; |
| 79 | struct sigaction { |
| 80 | sighandler_t sa_handler; |
| 81 | sigset_t sa_mask; |
| 82 | unsigned sa_flags; |
| 83 | }; |
| 84 | |
| 85 | HPPA: |
| 86 | |
| 87 | struct kernel_sigaction { |
| 88 | sighandler_t k_sa_handler; |
| 89 | unsigned long sa_flags; |
| 90 | sigset_t sa_mask; |
| 91 | }; |
| 92 | struct sigaction { |
| 93 | sighandler_t sa_handler; |
| 94 | unsigned long sa_flags; |
| 95 | sigset_t sa_mask; |
| 96 | }; |
| 97 | |
| 98 | The rest, kernel side: |
| 99 | |
| 100 | HAVE_SA_RESTORER #defined |
| 101 | struct old_kernel_sigaction { |
| 102 | sighandler_t k_sa_handler; |
| 103 | unsigned long sa_mask; |
| 104 | unsigned long sa_flags; |
| 105 | void (*sa_restorer)(void); |
| 106 | }; |
| 107 | struct kernel_sigaction { |
| 108 | sighandler_t k_sa_handler; |
| 109 | unsigned long sa_flags; |
| 110 | void (*sa_restorer)(void); |
| 111 | sigset_t sa_mask; |
| 112 | }; |
| 113 | |
| 114 | On userspace side, Sparc has special struct sigaction: |
| 115 | |
| 116 | struct sigaction { |
| 117 | sighandler_t sa_handler; |
| 118 | sigset_t sa_mask; |
| 119 | unsigned long sa_flags; |
| 120 | void (*sa_restorer)(void); /* Not used by Linux/Sparc */ |
| 121 | }; |
| 122 | |
| 123 | And finally the rest has: |
| 124 | |
| 125 | struct sigaction { |
| 126 | sighandler_t sa_handler; |
| 127 | sigset_t sa_mask; |
| 128 | int sa_flags; |
| 129 | void (*sa_restorer)(void); |
| 130 | }; |
| 131 | |
| 132 | Userspace sigset_t was uniformly defined as vector of longs |
| 133 | big enough to hold 1024 (!) bits - carried over from glibc. |
| 134 | Since the only arch whose struct kernel_sigaction contains sa_mask |
| 135 | not as a last member is MIPS, MIPS has special kernel_sigset_t, |
| 136 | which is an array of longs long enough for 128 bits. |
| 137 | Other arches still used userspace sigset_t in struct kernel_sigaction, |
| 138 | but it did not really matter because overlong kernel_sigaction |
| 139 | does not hurt in sigaction() [explained below]. |
| 140 | On kernel side, all arches define _NSIG to 65 (meaning |
| 141 | there are 64 signals, 1..64) except MIPS, which define it to 129. |
| 142 | |
| 143 | |
| 144 | Functions |
| 145 | |
| 146 | sigaction() [libc function] usually has two kernel_sigaction's |
| 147 | on stack and copy (userspace) struct sigaction members into |
| 148 | first one, executes syscall, then pulls out the result from |
| 149 | second one. This accomodates differences in layouts of structs. |
| 150 | |
| 151 | The only typically present quirk is what to do with sa_restorer. |
| 152 | |
| 153 | libc/sysdeps/linux/arm/sigaction.c |
| 154 | |
| 155 | if HAVE_SA_RESTORER and (sa_flags & SA_RESTORER) is not set, |
| 156 | sets sa_restorer to |
| 157 | (flags & SA_SIGINFO) ? __default_rt_sa_restorer : __default_sa_restorer, |
| 158 | and sets SA_RESTORER, |
| 159 | otherwise passes it as-is. Which is kinda strange, because AFAICS |
| 160 | HAVE_SA_RESTORER is *not* defined for ARM. |
| 161 | |
| 162 | libc/sysdeps/linux/i386/sigaction.c |
| 163 | |
| 164 | Forcibly sets SA_RESTORER and sa_restorer: |
| 165 | kact.sa_flags = act->sa_flags | SA_RESTORER; |
| 166 | kact.sa_restorer = ((act->sa_flags & SA_SIGINFO) ? &restore_rt : &restore); |
| 167 | |
| 168 | libc/sysdeps/linux/x86_64/sigaction.c |
| 169 | |
| 170 | Forcibly sets SA_RESTORER and sa_restorer: |
| 171 | kact.sa_flags = act->sa_flags | SA_RESTORER; |
| 172 | kact.sa_restorer = &restore_rt; |
| 173 | |
| 174 | libc/sysdeps/linux/mips/sigaction.c |
| 175 | |
| 176 | # ifdef HAVE_SA_RESTORER |
| 177 | # if _MIPS_SIM == _ABIO32 |
| 178 | kact.sa_restorer = act->sa_restorer; |
| 179 | # else |
| 180 | kact.sa_restorer = &restore_rt; |
| 181 | # endif |
| 182 | # endif |
| 183 | No confusion here, HAVE_SA_RESTORER is #defined for MIPS |
| 184 | |
| 185 | libc/sysdeps/linux/avr32/sigaction.c |
| 186 | |
| 187 | if (kact.sa_flags & SA_RESTORER) { |
| 188 | kact.sa_restorer = act->sa_restorer; |
| 189 | } else { |
| 190 | kact.sa_restorer = __default_rt_sa_restorer; |
| 191 | kact.sa_flags |= SA_RESTORER; |
| 192 | } |
| 193 | Does not check HAVE_SA_RESTORER, but avr32 falls |
| 194 | in "completely ordinary" category on both kernel and |
| 195 | userspace sides, and those have it defined. |
| 196 | |
| 197 | libc/sysdeps/linux/xtensa/sigaction.c |
| 198 | |
| 199 | if (kact.sa_flags & SA_RESTORER) { |
| 200 | kact.sa_restorer = act->sa_restorer; |
| 201 | } else { |
| 202 | kact.sa_restorer = __default_sa_restorer; |
| 203 | kact.sa_flags |= SA_RESTORER; |
| 204 | } |
| 205 | Thus, similar to avr32. |
| 206 | |
| 207 | libc/signal/sigaction.c (i.e. the all other arches) |
| 208 | |
| 209 | # ifdef HAVE_SA_RESTORER |
| 210 | kact.sa_restorer = act->sa_restorer; |
| 211 | # endif |
| 212 | Plain translation, just sa_restorer copy is protected |
| 213 | by HAVE_SA_RESTORER #define check. Looks like here |
| 214 | HAVE_SA_RESTORER will be undef'ed only for IA64, |
| 215 | Alpha an HPPA. |
| 216 | |
| 217 | |
| 218 | Proposed overhaul past 0.9.30 |
| 219 | |
| 220 | Since we can define libc-side structures at will: |
| 221 | make sigset_t and struct sigaction identical on kernel side and libc side |
| 222 | within each arch. If arches do not need special handling of sa_restorer, |
| 223 | then sigaction() can directly use passed struct sigaction as-is. |
| 224 | Otherwise, a copy is still needed, although sigaction() might have |
| 225 | just one struct kernel_sigaction on stack and use it both for passing |
| 226 | data to kernel and for receiving it back. Might save a few bytes. |
| 227 | |
| 228 | To this effect: |
| 229 | |
| 230 | * Make sigset_t size match kernel side on all arches. |
| 231 | This is easy since all arches have 64 signals and only MIPS has 128. |
| 232 | |
| 233 | * Modify libc/sysdeps/linux/$ARCH/bits/sigaction.h |
| 234 | so that its struct sigaction matches kernel's. If sa_restorer |
| 235 | field is present in libc but is missing in kernel_sigaction, |
| 236 | add it at the bottom in order to not mess up kernel_sigaction layout. |
| 237 | |
| 238 | * Modify libc/sysdeps/linux/$ARCH/sigaction.c |
| 239 | to implement the logic above. In "common" pseudo-arch |
| 240 | (libc/signal/sigaction.c file), |
| 241 | we would not even need to do any copying, as described above. |
| 242 | |
| 243 | * Document discovered arch quirks while debugging this mess. |
| 244 | |
| 245 | * struct old_kernel_sigaction can't be disposed of in a similar way, |
| 246 | we need to have userspace struct sigaction unchanged regardless |
| 247 | whether we use "old" or "new" kernel sigaction() syscall. |
| 248 | It's moot anyway because "old" one is long unused, it's from |
| 249 | pre-2.2 kernels. |