1
/* POSIX compatible signal blocking.
2
Copyright (C) 2006-2008 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 Lesser 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 Lesser General Public License for more details.
15
You should have received a copy of the GNU Lesser 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
typedef void (*handler_t) (int);
49
sigismember (const sigset_t *set, int sig)
51
if (sig >= 0 && sig < NSIG)
52
return (*set >> sig) & 1;
58
sigemptyset (sigset_t *set)
65
sigaddset (sigset_t *set, int sig)
67
if (sig >= 0 && sig < NSIG)
80
sigdelset (sigset_t *set, int sig)
82
if (sig >= 0 && sig < NSIG)
95
sigfillset (sigset_t *set)
97
*set = (2U << (NSIG - 1)) - 1;
101
/* Set of currently blocked signals. */
102
static volatile sigset_t blocked_set /* = 0 */;
104
/* Set of currently blocked and pending signals. */
105
static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
107
/* Signal handler that is installed for blocked signals. */
109
blocked_handler (int sig)
111
/* Reinstall the handler, in case the signal occurs multiple times
112
while blocked. There is an inherent race where an asynchronous
113
signal in between when the kernel uninstalled the handler and
114
when we reinstall it will trigger the default handler; oh
116
signal (sig, blocked_handler);
117
if (sig >= 0 && sig < NSIG)
118
pending_array[sig] = 1;
122
sigpending (sigset_t *set)
124
sigset_t pending = 0;
127
for (sig = 0; sig < NSIG; sig++)
128
if (pending_array[sig])
129
pending |= 1U << sig;
134
/* The previous signal handlers.
135
Only the array elements corresponding to blocked signals are relevant. */
136
static volatile handler_t old_handlers[NSIG];
139
sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
142
*old_set = blocked_set;
146
sigset_t new_blocked_set;
153
new_blocked_set = blocked_set | *set;
156
new_blocked_set = *set;
159
new_blocked_set = blocked_set & ~*set;
165
to_unblock = blocked_set & ~new_blocked_set;
166
to_block = new_blocked_set & ~blocked_set;
172
for (sig = 0; sig < NSIG; sig++)
173
if ((to_block >> sig) & 1)
175
pending_array[sig] = 0;
176
if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
177
blocked_set |= 1U << sig;
183
sig_atomic_t received[NSIG];
186
for (sig = 0; sig < NSIG; sig++)
187
if ((to_unblock >> sig) & 1)
189
if (signal (sig, old_handlers[sig]) != blocked_handler)
190
/* The application changed a signal handler while the signal
191
was blocked, bypassing our rpl_signal replacement.
192
We don't support this. */
194
received[sig] = pending_array[sig];
195
blocked_set &= ~(1U << sig);
196
pending_array[sig] = 0;
201
for (sig = 0; sig < NSIG; sig++)
209
/* Install the handler FUNC for signal SIG, and return the previous
212
rpl_signal (int sig, handler_t handler)
214
/* We must provide a wrapper, so that a user can query what handler
215
they installed even if that signal is currently blocked. */
216
if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
217
&& handler != SIG_ERR)
219
if (blocked_set & (1U << sig))
221
/* POSIX states that sigprocmask and signal are both
222
async-signal-safe. This is not true of our
223
implementation - there is a slight data race where an
224
asynchronous interrupt on signal A can occur after we
225
install blocked_handler but before we have updated
226
old_handlers for signal B, such that handler A can see
227
stale information if it calls signal(B). Oh well -
228
signal handlers really shouldn't try to manipulate the
229
installed handlers of unrelated signals. */
230
handler_t result = old_handlers[sig];
231
old_handlers[sig] = handler;
235
return signal (sig, handler);