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 /* 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 /* A signal handler. */
47 typedef void (*handler_t) (int signal);
50 sigismember (const sigset_t *set, int sig)
52 if (sig >= 0 && sig < NSIG)
53 return (*set >> sig) & 1;
59 sigemptyset (sigset_t *set)
66 sigaddset (sigset_t *set, int sig)
68 if (sig >= 0 && sig < NSIG)
81 sigdelset (sigset_t *set, int sig)
83 if (sig >= 0 && sig < NSIG)
96 sigfillset (sigset_t *set)
98 *set = (2U << (NSIG - 1)) - 1;
102 /* Set of currently blocked signals. */
103 static volatile sigset_t blocked_set /* = 0 */;
105 /* Set of currently blocked and pending signals. */
106 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
108 /* Signal handler that is installed for blocked signals. */
110 blocked_handler (int sig)
112 /* Reinstall the handler, in case the signal occurs multiple times
113 while blocked. There is an inherent race where an asynchronous
114 signal in between when the kernel uninstalled the handler and
115 when we reinstall it will trigger the default handler; oh
117 signal (sig, blocked_handler);
118 if (sig >= 0 && sig < NSIG)
119 pending_array[sig] = 1;
123 sigpending (sigset_t *set)
125 sigset_t pending = 0;
128 for (sig = 0; sig < NSIG; sig++)
129 if (pending_array[sig])
130 pending |= 1U << sig;
135 /* The previous signal handlers.
136 Only the array elements corresponding to blocked signals are relevant. */
137 static volatile handler_t old_handlers[NSIG];
140 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
143 *old_set = blocked_set;
147 sigset_t new_blocked_set;
154 new_blocked_set = blocked_set | *set;
157 new_blocked_set = *set;
160 new_blocked_set = blocked_set & ~*set;
166 to_unblock = blocked_set & ~new_blocked_set;
167 to_block = new_blocked_set & ~blocked_set;
173 for (sig = 0; sig < NSIG; sig++)
174 if ((to_block >> sig) & 1)
176 pending_array[sig] = 0;
177 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
178 blocked_set |= 1U << sig;
184 sig_atomic_t received[NSIG];
187 for (sig = 0; sig < NSIG; sig++)
188 if ((to_unblock >> sig) & 1)
190 if (signal (sig, old_handlers[sig]) != blocked_handler)
191 /* The application changed a signal handler while the signal
192 was blocked. 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;
234 return signal (sig, handler);