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 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 #include "sig-handler.h"
29 /* We assume that a platform without POSIX signal blocking functions
30 also does not have the POSIX sigaction() function, only the
31 signal() function. We also assume signal() has SysV semantics,
32 where any handler is uninstalled prior to being invoked. This is
33 true for Woe32 platforms. */
35 /* We use raw signal(), but also provide a wrapper rpl_signal() so
36 that applications can query or change a blocked signal. */
39 /* Provide invalid signal numbers as fallbacks if the uncatchable
40 signals are not defined. */
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 sa_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. We don't support this. */
193 received[sig] = pending_array[sig];
194 blocked_set &= ~(1U << sig);
195 pending_array[sig] = 0;
200 for (sig = 0; sig < NSIG; sig++)
208 /* Install the handler FUNC for signal SIG, and return the previous
211 rpl_signal (int sig, sa_handler_t handler)
213 /* We must provide a wrapper, so that a user can query what handler
214 they installed even if that signal is currently blocked. */
215 if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
216 && handler != SIG_ERR)
218 if (blocked_set & (1U << sig))
220 /* POSIX states that sigprocmask and signal are both
221 async-signal-safe. This is not true of our
222 implementation - there is a slight data race where an
223 asynchronous interrupt on signal A can occur after we
224 install blocked_handler but before we have updated
225 old_handlers for signal B, such that handler A can see
226 stale information if it calls signal(B). Oh well -
227 signal handlers really shouldn't try to manipulate the
228 installed handlers of unrelated signals. */
229 sa_handler_t result = old_handlers[sig];
230 old_handlers[sig] = handler;
233 return signal (sig, handler);