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>