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 typedef void (*handler_t) (int);
48 /* Handling of gnulib defined signals. */
50 #if GNULIB_defined_SIGPIPE
51 static handler_t SIGPIPE_handler = SIG_DFL;
54 #if GNULIB_defined_SIGPIPE
56 ext_signal (int sig, handler_t handler)
62 handler_t old_handler = SIGPIPE_handler;
63 SIGPIPE_handler = handler;
66 default: /* System defined signal */
67 return signal (sig, handler);
70 # define signal ext_signal
74 sigismember (const sigset_t *set, int sig)
76 if (sig >= 0 && sig < NSIG)
77 return (*set >> sig) & 1;
83 sigemptyset (sigset_t *set)
90 sigaddset (sigset_t *set, int sig)
92 if (sig >= 0 && sig < NSIG)
105 sigdelset (sigset_t *set, int sig)
107 if (sig >= 0 && sig < NSIG)
109 *set &= ~(1U << sig);
120 sigfillset (sigset_t *set)
122 *set = (2U << (NSIG - 1)) - 1;
126 /* Set of currently blocked signals. */
127 static volatile sigset_t blocked_set /* = 0 */;
129 /* Set of currently blocked and pending signals. */
130 static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
132 /* Signal handler that is installed for blocked signals. */
134 blocked_handler (int sig)
136 /* Reinstall the handler, in case the signal occurs multiple times
137 while blocked. There is an inherent race where an asynchronous
138 signal in between when the kernel uninstalled the handler and
139 when we reinstall it will trigger the default handler; oh
141 signal (sig, blocked_handler);
142 if (sig >= 0 && sig < NSIG)
143 pending_array[sig] = 1;
147 sigpending (sigset_t *set)
149 sigset_t pending = 0;
152 for (sig = 0; sig < NSIG; sig++)
153 if (pending_array[sig])
154 pending |= 1U << sig;
159 /* The previous signal handlers.
160 Only the array elements corresponding to blocked signals are relevant. */
161 static volatile handler_t old_handlers[NSIG];
164 sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
167 *old_set = blocked_set;
171 sigset_t new_blocked_set;
178 new_blocked_set = blocked_set | *set;
181 new_blocked_set = *set;
184 new_blocked_set = blocked_set & ~*set;
190 to_unblock = blocked_set & ~new_blocked_set;
191 to_block = new_blocked_set & ~blocked_set;
197 for (sig = 0; sig < NSIG; sig++)
198 if ((to_block >> sig) & 1)
200 pending_array[sig] = 0;
201 if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
202 blocked_set |= 1U << sig;
208 sig_atomic_t received[NSIG];
211 for (sig = 0; sig < NSIG; sig++)
212 if ((to_unblock >> sig) & 1)
214 if (signal (sig, old_handlers[sig]) != blocked_handler)
215 /* The application changed a signal handler while the signal
216 was blocked, bypassing our rpl_signal replacement.
217 We don't support this. */
219 received[sig] = pending_array[sig];
220 blocked_set &= ~(1U << sig);
221 pending_array[sig] = 0;
226 for (sig = 0; sig < NSIG; sig++)
234 /* Install the handler FUNC for signal SIG, and return the previous
237 rpl_signal (int sig, handler_t handler)
239 /* We must provide a wrapper, so that a user can query what handler
240 they installed even if that signal is currently blocked. */
241 if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
242 && handler != SIG_ERR)
244 if (blocked_set & (1U << sig))
246 /* POSIX states that sigprocmask and signal are both
247 async-signal-safe. This is not true of our
248 implementation - there is a slight data race where an
249 asynchronous interrupt on signal A can occur after we
250 install blocked_handler but before we have updated
251 old_handlers for signal B, such that handler A can see
252 stale information if it calls signal(B). Oh well -
253 signal handlers really shouldn't try to manipulate the
254 installed handlers of unrelated signals. */
255 handler_t result = old_handlers[sig];
256 old_handlers[sig] = handler;
260 return signal (sig, handler);
269 #if GNULIB_defined_SIGPIPE
270 /* Raise the signal SIG. */
278 if (blocked_set & (1U << sig))
279 pending_array[sig] = 1;
282 handler_t handler = SIGPIPE_handler;
283 if (handler == SIG_DFL)
284 exit (128 + SIGPIPE);
285 else if (handler != SIG_IGN)
289 default: /* System defined signal */