Annotation of embedaddon/libiconv/srclib/sigprocmask.c, revision 1.1.1.3
1.1 misho 1: /* POSIX compatible signal blocking.
1.1.1.3 ! misho 2: Copyright (C) 2006-2019 Free Software Foundation, Inc.
1.1 misho 3: Written by Bruno Haible <bruno@clisp.org>, 2006.
4:
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.
9:
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.
14:
15: You should have received a copy of the GNU General Public License
1.1.1.3 ! misho 16: along with this program. If not, see <https://www.gnu.org/licenses/>. */
1.1 misho 17:
18: #include <config.h>
19:
20: /* Specification. */
21: #include <signal.h>
22:
23: #include <errno.h>
24: #include <stdint.h>
25: #include <stdlib.h>
26:
1.1.1.3 ! misho 27: #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
! 28: # include "msvc-inval.h"
! 29: #endif
! 30:
1.1 misho 31: /* We assume that a platform without POSIX signal blocking functions
32: also does not have the POSIX sigaction() function, only the
33: signal() function. We also assume signal() has SysV semantics,
34: where any handler is uninstalled prior to being invoked. This is
1.1.1.3 ! misho 35: true for native Windows platforms. */
1.1 misho 36:
37: /* We use raw signal(), but also provide a wrapper rpl_signal() so
38: that applications can query or change a blocked signal. */
39: #undef signal
40:
41: /* Provide invalid signal numbers as fallbacks if the uncatchable
42: signals are not defined. */
43: #ifndef SIGKILL
44: # define SIGKILL (-1)
45: #endif
46: #ifndef SIGSTOP
47: # define SIGSTOP (-1)
48: #endif
49:
50: /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
51: for the signal SIGABRT. Only one signal handler is stored for both
52: SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */
1.1.1.3 ! misho 53: #if defined _WIN32 && ! defined __CYGWIN__
1.1 misho 54: # undef SIGABRT_COMPAT
55: # define SIGABRT_COMPAT 6
56: #endif
57: #ifdef SIGABRT_COMPAT
58: # define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT)
59: #else
60: # define SIGABRT_COMPAT_MASK 0
61: #endif
62:
63: typedef void (*handler_t) (int);
64:
1.1.1.3 ! misho 65: #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
! 66: static handler_t
! 67: signal_nothrow (int sig, handler_t handler)
! 68: {
! 69: handler_t result;
! 70:
! 71: TRY_MSVC_INVAL
! 72: {
! 73: result = signal (sig, handler);
! 74: }
! 75: CATCH_MSVC_INVAL
! 76: {
! 77: result = SIG_ERR;
! 78: errno = EINVAL;
! 79: }
! 80: DONE_MSVC_INVAL;
! 81:
! 82: return result;
! 83: }
! 84: # define signal signal_nothrow
! 85: #endif
! 86:
1.1 misho 87: /* Handling of gnulib defined signals. */
88:
89: #if GNULIB_defined_SIGPIPE
90: static handler_t SIGPIPE_handler = SIG_DFL;
91: #endif
92:
93: #if GNULIB_defined_SIGPIPE
94: static handler_t
95: ext_signal (int sig, handler_t handler)
96: {
97: switch (sig)
98: {
99: case SIGPIPE:
100: {
1.1.1.2 misho 101: handler_t old_handler = SIGPIPE_handler;
102: SIGPIPE_handler = handler;
103: return old_handler;
1.1 misho 104: }
105: default: /* System defined signal */
106: return signal (sig, handler);
107: }
108: }
1.1.1.3 ! misho 109: # undef signal
1.1 misho 110: # define signal ext_signal
111: #endif
112:
113: int
114: sigismember (const sigset_t *set, int sig)
115: {
116: if (sig >= 0 && sig < NSIG)
117: {
118: #ifdef SIGABRT_COMPAT
119: if (sig == SIGABRT_COMPAT)
1.1.1.2 misho 120: sig = SIGABRT;
1.1 misho 121: #endif
122:
123: return (*set >> sig) & 1;
124: }
125: else
126: return 0;
127: }
128:
129: int
130: sigemptyset (sigset_t *set)
131: {
132: *set = 0;
133: return 0;
134: }
135:
136: int
137: sigaddset (sigset_t *set, int sig)
138: {
139: if (sig >= 0 && sig < NSIG)
140: {
141: #ifdef SIGABRT_COMPAT
142: if (sig == SIGABRT_COMPAT)
1.1.1.2 misho 143: sig = SIGABRT;
1.1 misho 144: #endif
145:
146: *set |= 1U << sig;
147: return 0;
148: }
149: else
150: {
151: errno = EINVAL;
152: return -1;
153: }
154: }
155:
156: int
157: sigdelset (sigset_t *set, int sig)
158: {
159: if (sig >= 0 && sig < NSIG)
160: {
161: #ifdef SIGABRT_COMPAT
162: if (sig == SIGABRT_COMPAT)
1.1.1.2 misho 163: sig = SIGABRT;
1.1 misho 164: #endif
165:
166: *set &= ~(1U << sig);
167: return 0;
168: }
169: else
170: {
171: errno = EINVAL;
172: return -1;
173: }
174: }
175:
176:
177: int
178: sigfillset (sigset_t *set)
179: {
180: *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK;
181: return 0;
182: }
183:
184: /* Set of currently blocked signals. */
185: static volatile sigset_t blocked_set /* = 0 */;
186:
187: /* Set of currently blocked and pending signals. */
188: static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */;
189:
190: /* Signal handler that is installed for blocked signals. */
191: static void
192: blocked_handler (int sig)
193: {
194: /* Reinstall the handler, in case the signal occurs multiple times
195: while blocked. There is an inherent race where an asynchronous
196: signal in between when the kernel uninstalled the handler and
197: when we reinstall it will trigger the default handler; oh
198: well. */
199: signal (sig, blocked_handler);
200: if (sig >= 0 && sig < NSIG)
201: pending_array[sig] = 1;
202: }
203:
204: int
205: sigpending (sigset_t *set)
206: {
207: sigset_t pending = 0;
208: int sig;
209:
210: for (sig = 0; sig < NSIG; sig++)
211: if (pending_array[sig])
212: pending |= 1U << sig;
213: *set = pending;
214: return 0;
215: }
216:
217: /* The previous signal handlers.
218: Only the array elements corresponding to blocked signals are relevant. */
219: static volatile handler_t old_handlers[NSIG];
220:
221: int
222: sigprocmask (int operation, const sigset_t *set, sigset_t *old_set)
223: {
224: if (old_set != NULL)
225: *old_set = blocked_set;
226:
227: if (set != NULL)
228: {
229: sigset_t new_blocked_set;
230: sigset_t to_unblock;
231: sigset_t to_block;
232:
233: switch (operation)
1.1.1.2 misho 234: {
235: case SIG_BLOCK:
236: new_blocked_set = blocked_set | *set;
237: break;
238: case SIG_SETMASK:
239: new_blocked_set = *set;
240: break;
241: case SIG_UNBLOCK:
242: new_blocked_set = blocked_set & ~*set;
243: break;
244: default:
245: errno = EINVAL;
246: return -1;
247: }
1.1 misho 248: to_unblock = blocked_set & ~new_blocked_set;
249: to_block = new_blocked_set & ~blocked_set;
250:
251: if (to_block != 0)
1.1.1.2 misho 252: {
253: int sig;
1.1 misho 254:
1.1.1.2 misho 255: for (sig = 0; sig < NSIG; sig++)
256: if ((to_block >> sig) & 1)
257: {
258: pending_array[sig] = 0;
259: if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR)
260: blocked_set |= 1U << sig;
261: }
262: }
1.1 misho 263:
264: if (to_unblock != 0)
1.1.1.2 misho 265: {
266: sig_atomic_t received[NSIG];
267: int sig;
268:
269: for (sig = 0; sig < NSIG; sig++)
270: if ((to_unblock >> sig) & 1)
271: {
272: if (signal (sig, old_handlers[sig]) != blocked_handler)
273: /* The application changed a signal handler while the signal
274: was blocked, bypassing our rpl_signal replacement.
275: We don't support this. */
276: abort ();
277: received[sig] = pending_array[sig];
278: blocked_set &= ~(1U << sig);
279: pending_array[sig] = 0;
280: }
281: else
282: received[sig] = 0;
283:
284: for (sig = 0; sig < NSIG; sig++)
285: if (received[sig])
286: raise (sig);
287: }
1.1 misho 288: }
289: return 0;
290: }
291:
292: /* Install the handler FUNC for signal SIG, and return the previous
293: handler. */
294: handler_t
295: rpl_signal (int sig, handler_t handler)
296: {
297: /* We must provide a wrapper, so that a user can query what handler
298: they installed even if that signal is currently blocked. */
299: if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP
300: && handler != SIG_ERR)
301: {
302: #ifdef SIGABRT_COMPAT
303: if (sig == SIGABRT_COMPAT)
1.1.1.2 misho 304: sig = SIGABRT;
1.1 misho 305: #endif
306:
307: if (blocked_set & (1U << sig))
1.1.1.2 misho 308: {
309: /* POSIX states that sigprocmask and signal are both
310: async-signal-safe. This is not true of our
311: implementation - there is a slight data race where an
312: asynchronous interrupt on signal A can occur after we
313: install blocked_handler but before we have updated
314: old_handlers for signal B, such that handler A can see
315: stale information if it calls signal(B). Oh well -
316: signal handlers really shouldn't try to manipulate the
317: installed handlers of unrelated signals. */
318: handler_t result = old_handlers[sig];
319: old_handlers[sig] = handler;
320: return result;
321: }
1.1 misho 322: else
1.1.1.2 misho 323: return signal (sig, handler);
1.1 misho 324: }
325: else
326: {
327: errno = EINVAL;
328: return SIG_ERR;
329: }
330: }
331:
332: #if GNULIB_defined_SIGPIPE
1.1.1.3 ! misho 333: /* Raise the signal SIGPIPE. */
1.1 misho 334: int
1.1.1.3 ! misho 335: _gl_raise_SIGPIPE (void)
1.1 misho 336: {
1.1.1.3 ! misho 337: if (blocked_set & (1U << SIGPIPE))
! 338: pending_array[SIGPIPE] = 1;
! 339: else
1.1 misho 340: {
1.1.1.3 ! misho 341: handler_t handler = SIGPIPE_handler;
! 342: if (handler == SIG_DFL)
! 343: exit (128 + SIGPIPE);
! 344: else if (handler != SIG_IGN)
! 345: (*handler) (SIGPIPE);
1.1 misho 346: }
1.1.1.3 ! misho 347: return 0;
1.1 misho 348: }
349: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>