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