1 /* POSIX compatible signal blocking. 2 Copyright (C) 2006-2012 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno (at) clisp.org>, 2006. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include <config.h> 19 20 /* Specification. */ 21 #include <signal.h> 22 23 #include <errno.h> 24 #include <stdint.h> 25 #include <stdlib.h> 26 27 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER 28 # include "msvc-inval.h" 29 #endif 30 31 /* We assume that a platform without POSIX signal blocking functions 32 also does not have the POSIX sigaction() function, only the 33 signal() function. We also assume signal() has SysV semantics, 34 where any handler is uninstalled prior to being invoked. This is 35 true for native Windows platforms. */ 36 37 /* We use raw signal(), but also provide a wrapper rpl_signal() so 38 that applications can query or change a blocked signal. */ 39 #undef signal 40 41 /* Provide invalid signal numbers as fallbacks if the uncatchable 42 signals are not defined. */ 43 #ifndef SIGKILL 44 # define SIGKILL (-1) 45 #endif 46 #ifndef SIGSTOP 47 # define SIGSTOP (-1) 48 #endif 49 50 /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias 51 for the signal SIGABRT. Only one signal handler is stored for both 52 SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ 53 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 54 # undef SIGABRT_COMPAT 55 # define SIGABRT_COMPAT 6 56 #endif 57 #ifdef SIGABRT_COMPAT 58 # define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT) 59 #else 60 # define SIGABRT_COMPAT_MASK 0 61 #endif 62 63 typedef void (*handler_t) (int); 64 65 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER 66 static handler_t 67 signal_nothrow (int sig, handler_t handler) 68 { 69 handler_t result; 70 71 TRY_MSVC_INVAL 72 { 73 result = signal (sig, handler); 74 } 75 CATCH_MSVC_INVAL 76 { 77 result = SIG_ERR; 78 errno = EINVAL; 79 } 80 DONE_MSVC_INVAL; 81 82 return result; 83 } 84 # define signal signal_nothrow 85 #endif 86 87 /* Handling of gnulib defined signals. */ 88 89 #if GNULIB_defined_SIGPIPE 90 static handler_t SIGPIPE_handler = SIG_DFL; 91 #endif 92 93 #if GNULIB_defined_SIGPIPE 94 static handler_t 95 ext_signal (int sig, handler_t handler) 96 { 97 switch (sig) 98 { 99 case SIGPIPE: 100 { 101 handler_t old_handler = SIGPIPE_handler; 102 SIGPIPE_handler = handler; 103 return old_handler; 104 } 105 default: /* System defined signal */ 106 return signal (sig, handler); 107 } 108 } 109 # undef signal 110 # define signal ext_signal 111 #endif 112 113 int 114 sigismember (const sigset_t *set, int sig) 115 { 116 if (sig >= 0 && sig < NSIG) 117 { 118 #ifdef SIGABRT_COMPAT 119 if (sig == SIGABRT_COMPAT) 120 sig = SIGABRT; 121 #endif 122 123 return (*set >> sig) & 1; 124 } 125 else 126 return 0; 127 } 128 129 int 130 sigemptyset (sigset_t *set) 131 { 132 *set = 0; 133 return 0; 134 } 135 136 int 137 sigaddset (sigset_t *set, int sig) 138 { 139 if (sig >= 0 && sig < NSIG) 140 { 141 #ifdef SIGABRT_COMPAT 142 if (sig == SIGABRT_COMPAT) 143 sig = SIGABRT; 144 #endif 145 146 *set |= 1U << sig; 147 return 0; 148 } 149 else 150 { 151 errno = EINVAL; 152 return -1; 153 } 154 } 155 156 int 157 sigdelset (sigset_t *set, int sig) 158 { 159 if (sig >= 0 && sig < NSIG) 160 { 161 #ifdef SIGABRT_COMPAT 162 if (sig == SIGABRT_COMPAT) 163 sig = SIGABRT; 164 #endif 165 166 *set &= ~(1U << sig); 167 return 0; 168 } 169 else 170 { 171 errno = EINVAL; 172 return -1; 173 } 174 } 175 176 177 int 178 sigfillset (sigset_t *set) 179 { 180 *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK; 181 return 0; 182 } 183 184 /* Set of currently blocked signals. */ 185 static volatile sigset_t blocked_set /* = 0 */; 186 187 /* Set of currently blocked and pending signals. */ 188 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; 189 190 /* Signal handler that is installed for blocked signals. */ 191 static void 192 blocked_handler (int sig) 193 { 194 /* Reinstall the handler, in case the signal occurs multiple times 195 while blocked. There is an inherent race where an asynchronous 196 signal in between when the kernel uninstalled the handler and 197 when we reinstall it will trigger the default handler; oh 198 well. */ 199 signal (sig, blocked_handler); 200 if (sig >= 0 && sig < NSIG) 201 pending_array[sig] = 1; 202 } 203 204 int 205 sigpending (sigset_t *set) 206 { 207 sigset_t pending = 0; 208 int sig; 209 210 for (sig = 0; sig < NSIG; sig++) 211 if (pending_array[sig]) 212 pending |= 1U << sig; 213 *set = pending; 214 return 0; 215 } 216 217 /* The previous signal handlers. 218 Only the array elements corresponding to blocked signals are relevant. */ 219 static volatile handler_t old_handlers[NSIG]; 220 221 int 222 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) 223 { 224 if (old_set != NULL) 225 *old_set = blocked_set; 226 227 if (set != NULL) 228 { 229 sigset_t new_blocked_set; 230 sigset_t to_unblock; 231 sigset_t to_block; 232 233 switch (operation) 234 { 235 case SIG_BLOCK: 236 new_blocked_set = blocked_set | *set; 237 break; 238 case SIG_SETMASK: 239 new_blocked_set = *set; 240 break; 241 case SIG_UNBLOCK: 242 new_blocked_set = blocked_set & ~*set; 243 break; 244 default: 245 errno = EINVAL; 246 return -1; 247 } 248 to_unblock = blocked_set & ~new_blocked_set; 249 to_block = new_blocked_set & ~blocked_set; 250 251 if (to_block != 0) 252 { 253 int sig; 254 255 for (sig = 0; sig < NSIG; sig++) 256 if ((to_block >> sig) & 1) 257 { 258 pending_array[sig] = 0; 259 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) 260 blocked_set |= 1U << sig; 261 } 262 } 263 264 if (to_unblock != 0) 265 { 266 sig_atomic_t received[NSIG]; 267 int sig; 268 269 for (sig = 0; sig < NSIG; sig++) 270 if ((to_unblock >> sig) & 1) 271 { 272 if (signal (sig, old_handlers[sig]) != blocked_handler) 273 /* The application changed a signal handler while the signal 274 was blocked, bypassing our rpl_signal replacement. 275 We don't support this. */ 276 abort (); 277 received[sig] = pending_array[sig]; 278 blocked_set &= ~(1U << sig); 279 pending_array[sig] = 0; 280 } 281 else 282 received[sig] = 0; 283 284 for (sig = 0; sig < NSIG; sig++) 285 if (received[sig]) 286 raise (sig); 287 } 288 } 289 return 0; 290 } 291 292 /* Install the handler FUNC for signal SIG, and return the previous 293 handler. */ 294 handler_t 295 rpl_signal (int sig, handler_t handler) 296 { 297 /* We must provide a wrapper, so that a user can query what handler 298 they installed even if that signal is currently blocked. */ 299 if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP 300 && handler != SIG_ERR) 301 { 302 #ifdef SIGABRT_COMPAT 303 if (sig == SIGABRT_COMPAT) 304 sig = SIGABRT; 305 #endif 306 307 if (blocked_set & (1U << sig)) 308 { 309 /* POSIX states that sigprocmask and signal are both 310 async-signal-safe. This is not true of our 311 implementation - there is a slight data race where an 312 asynchronous interrupt on signal A can occur after we 313 install blocked_handler but before we have updated 314 old_handlers for signal B, such that handler A can see 315 stale information if it calls signal(B). Oh well - 316 signal handlers really shouldn't try to manipulate the 317 installed handlers of unrelated signals. */ 318 handler_t result = old_handlers[sig]; 319 old_handlers[sig] = handler; 320 return result; 321 } 322 else 323 return signal (sig, handler); 324 } 325 else 326 { 327 errno = EINVAL; 328 return SIG_ERR; 329 } 330 } 331 332 #if GNULIB_defined_SIGPIPE 333 /* Raise the signal SIGPIPE. */ 334 int 335 _gl_raise_SIGPIPE (void) 336 { 337 if (blocked_set & (1U << SIGPIPE)) 338 pending_array[SIGPIPE] = 1; 339 else 340 { 341 handler_t handler = SIGPIPE_handler; 342 if (handler == SIG_DFL) 343 exit (128 + SIGPIPE); 344 else if (handler != SIG_IGN) 345 (*handler) (SIGPIPE); 346 } 347 return 0; 348 } 349 #endif 350