File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / sigprocmask.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 09:29:43 2012 UTC (12 years, 1 month ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_14p0, v1_14, HEAD
libiconv v1.14

    1: /* POSIX compatible signal blocking.
    2:    Copyright (C) 2006-2011 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>