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>