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>