1
/* POSIX compatible signal blocking.
2
Copyright (C) 2006-2010 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
/* Handling of gnulib defined signals. */
63
#if GNULIB_defined_SIGPIPE
64
static handler_t SIGPIPE_handler = SIG_DFL;
67
#if GNULIB_defined_SIGPIPE
69
ext_signal (int sig, handler_t handler)
75
handler_t old_handler = SIGPIPE_handler;
76
SIGPIPE_handler = handler;
79
default: /* System defined signal */
80
return signal (sig, handler);
83
# define signal ext_signal
87
sigismember (const sigset_t *set, int sig)
89
if (sig >= 0 && sig < NSIG)
92
if (sig == SIGABRT_COMPAT)
96
return (*set >> sig) & 1;
103
sigemptyset (sigset_t *set)
110
sigaddset (sigset_t *set, int sig)
112
if (sig >= 0 && sig < NSIG)
114
#ifdef SIGABRT_COMPAT
115
if (sig == SIGABRT_COMPAT)
130
sigdelset (sigset_t *set, int sig)
132
if (sig >= 0 && sig < NSIG)
134
#ifdef SIGABRT_COMPAT
135
if (sig == SIGABRT_COMPAT)
139
*set &= ~(1U << sig);
151
sigfillset (sigset_t *set)
153
*set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
157
/* Set of currently blocked signals. */
158
static volatile sigset_t blocked_set /* = 0 */;
160
/* Set of currently blocked and pending signals. */
161
static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
163
/* Signal handler that is installed for blocked signals. */
165
blocked_handler (int sig)
167
/* Reinstall the handler, in case the signal occurs multiple times
168
while blocked. There is an inherent race where an asynchronous
169
signal in between when the kernel uninstalled the handler and
170
when we reinstall it will trigger the default handler; oh
172
signal (sig, blocked_handler);
173
if (sig >= 0 && sig < NSIG)
174
pending_array[sig] = 1;
178
sigpending (sigset_t *set)
180
sigset_t pending = 0;
183
for (sig = 0; sig < NSIG; sig++)
184
if (pending_array[sig])
185
pending |= 1U << sig;
190
/* The previous signal handlers.
191
Only the array elements corresponding to blocked signals are relevant. */
192
static volatile handler_t old_handlers[NSIG];
195
sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
198
*old_set = blocked_set;
202
sigset_t new_blocked_set;
209
new_blocked_set = blocked_set | *set;
212
new_blocked_set = *set;
215
new_blocked_set = blocked_set & ~*set;
221
to_unblock = blocked_set & ~new_blocked_set;
222
to_block = new_blocked_set & ~blocked_set;
228
for (sig = 0; sig < NSIG; sig++)
229
if ((to_block >> sig) & 1)
231
pending_array[sig] = 0;
232
if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
233
blocked_set |= 1U << sig;
239
sig_atomic_t received[NSIG];
242
for (sig = 0; sig < NSIG; sig++)
243
if ((to_unblock >> sig) & 1)
245
if (signal (sig, old_handlers[sig]) != blocked_handler)
246
/* The application changed a signal handler while the signal
247
was blocked, bypassing our rpl_signal replacement.
248
We don't support this. */
250
received[sig] = pending_array[sig];
251
blocked_set &= ~(1U << sig);
252
pending_array[sig] = 0;
257
for (sig = 0; sig < NSIG; sig++)
265
/* Install the handler FUNC for signal SIG, and return the previous
268
rpl_signal (int sig, handler_t handler)
270
/* We must provide a wrapper, so that a user can query what handler
271
they installed even if that signal is currently blocked. */
272
if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
273
&& handler != SIG_ERR)
275
#ifdef SIGABRT_COMPAT
276
if (sig == SIGABRT_COMPAT)
280
if (blocked_set & (1U << sig))
282
/* POSIX states that sigprocmask and signal are both
283
async-signal-safe. This is not true of our
284
implementation - there is a slight data race where an
285
asynchronous interrupt on signal A can occur after we
286
install blocked_handler but before we have updated
287
old_handlers for signal B, such that handler A can see
288
stale information if it calls signal(B). Oh well -
289
signal handlers really shouldn't try to manipulate the
290
installed handlers of unrelated signals. */
291
handler_t result = old_handlers[sig];
292
old_handlers[sig] = handler;
296
return signal (sig, handler);
305
#if GNULIB_defined_SIGPIPE
306
/* Raise the signal SIG. */
314
if (blocked_set & (1U << sig))
315
pending_array[sig] = 1;
318
handler_t handler = SIGPIPE_handler;
319
if (handler == SIG_DFL)
320
exit (128 + SIGPIPE);
321
else if (handler != SIG_IGN)
325
default: /* System defined signal */