Annotation of embedaddon/libiconv/srclib/sigprocmask.c, revision 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>