1 /* POSIX compatible signal blocking.
2 Copyright (C) 2006-2011 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
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.
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.
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/>. */
27 /* We assume that a platform without POSIX signal blocking functions
28 also does not have the POSIX sigaction() function, only the
29 signal() function. We also assume signal() has SysV semantics,
30 where any handler is uninstalled prior to being invoked. This is
31 true for Woe32 platforms. */
33 /* We use raw signal(), but also provide a wrapper rpl_signal() so
34 that applications can query or change a blocked signal. */
37 /* Provide invalid signal numbers as fallbacks if the uncatchable
38 signals are not defined. */
46 /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
47 for the signal SIGABRT. Only one signal handler is stored for both
48 SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */
49 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
50 # undef SIGABRT_COMPAT
51 # define SIGABRT_COMPAT 6
54 # define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
56 # define SIGABRT_COMPAT_MASK 0
59 typedef void (*handler_t) (int);
61 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
62 # include "msvc-inval.h"
64 static inline handler_t
65 signal_nothrow (int sig, handler_t handler)
71 result = signal (sig, handler);
82 # define signal signal_nothrow
85 /* Handling of gnulib defined signals. */
87 #if GNULIB_defined_SIGPIPE
88 static handler_t SIGPIPE_handler = SIG_DFL;
91 #if GNULIB_defined_SIGPIPE
93 ext_signal (int sig, handler_t handler)
99 handler_t old_handler = SIGPIPE_handler;
100 SIGPIPE_handler = handler;
103 default: /* System defined signal */
104 return signal (sig, handler);
108 # define signal ext_signal
112 sigismember (const sigset_t *set, int sig)
114 if (sig >= 0 && sig < NSIG)
116 #ifdef SIGABRT_COMPAT
117 if (sig == SIGABRT_COMPAT)
121 return (*set >> sig) & 1;
128 sigemptyset (sigset_t *set)
135 sigaddset (sigset_t *set, int sig)
137 if (sig >= 0 && sig < NSIG)
139 #ifdef SIGABRT_COMPAT
140 if (sig == SIGABRT_COMPAT)
155 sigdelset (sigset_t *set, int sig)
157 if (sig >= 0 && sig < NSIG)
159 #ifdef SIGABRT_COMPAT
160 if (sig == SIGABRT_COMPAT)
164 *set &= ~(1U << sig);
176 sigfillset (sigset_t *set)
178 *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
182 /* Set of currently blocked signals. */
183 static volatile sigset_t blocked_set /* = 0 */;
185 /* Set of currently blocked and pending signals. */
186 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
188 /* Signal handler that is installed for blocked signals. */
190 blocked_handler (int sig)
192 /* Reinstall the handler, in case the signal occurs multiple times
193 while blocked. There is an inherent race where an asynchronous
194 signal in between when the kernel uninstalled the handler and
195 when we reinstall it will trigger the default handler; oh
197 signal (sig, blocked_handler);
198 if (sig >= 0 && sig < NSIG)
199 pending_array[sig] = 1;
203 sigpending (sigset_t *set)
205 sigset_t pending = 0;
208 for (sig = 0; sig < NSIG; sig++)
209 if (pending_array[sig])
210 pending |= 1U << sig;
215 /* The previous signal handlers.
216 Only the array elements corresponding to blocked signals are relevant. */
217 static volatile handler_t old_handlers[NSIG];
220 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
223 *old_set = blocked_set;
227 sigset_t new_blocked_set;
234 new_blocked_set = blocked_set | *set;
237 new_blocked_set = *set;
240 new_blocked_set = blocked_set & ~*set;
246 to_unblock = blocked_set & ~new_blocked_set;
247 to_block = new_blocked_set & ~blocked_set;
253 for (sig = 0; sig < NSIG; sig++)
254 if ((to_block >> sig) & 1)
256 pending_array[sig] = 0;
257 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
258 blocked_set |= 1U << sig;
264 sig_atomic_t received[NSIG];
267 for (sig = 0; sig < NSIG; sig++)
268 if ((to_unblock >> sig) & 1)
270 if (signal (sig, old_handlers[sig]) != blocked_handler)
271 /* The application changed a signal handler while the signal
272 was blocked, bypassing our rpl_signal replacement.
273 We don't support this. */
275 received[sig] = pending_array[sig];
276 blocked_set &= ~(1U << sig);
277 pending_array[sig] = 0;
282 for (sig = 0; sig < NSIG; sig++)
290 /* Install the handler FUNC for signal SIG, and return the previous
293 rpl_signal (int sig, handler_t handler)
295 /* We must provide a wrapper, so that a user can query what handler
296 they installed even if that signal is currently blocked. */
297 if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
298 && handler != SIG_ERR)
300 #ifdef SIGABRT_COMPAT
301 if (sig == SIGABRT_COMPAT)
305 if (blocked_set & (1U << sig))
307 /* POSIX states that sigprocmask and signal are both
308 async-signal-safe. This is not true of our
309 implementation - there is a slight data race where an
310 asynchronous interrupt on signal A can occur after we
311 install blocked_handler but before we have updated
312 old_handlers for signal B, such that handler A can see
313 stale information if it calls signal(B). Oh well -
314 signal handlers really shouldn't try to manipulate the
315 installed handlers of unrelated signals. */
316 handler_t result = old_handlers[sig];
317 old_handlers[sig] = handler;
321 return signal (sig, handler);
330 #if GNULIB_defined_SIGPIPE
331 /* Raise the signal SIG. */
339 if (blocked_set & (1U << sig))
340 pending_array[sig] = 1;
343 handler_t handler = SIGPIPE_handler;
344 if (handler == SIG_DFL)
345 exit (128 + SIGPIPE);
346 else if (handler != SIG_IGN)
350 default: /* System defined signal */