File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / sigprocmask.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 13:38:46 2021 UTC (3 years, 3 months ago) by misho
Branches: libiconv, MAIN
CVS tags: v1_16p0, HEAD
libiconv 1.16

    1: /* POSIX compatible signal blocking.
    2:    Copyright (C) 2006-2019 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 <https://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: #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
   28: # include "msvc-inval.h"
   29: #endif
   30: 
   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
   35:    true for native Windows platforms.  */
   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.  */
   53: #if defined _WIN32 && ! defined __CYGWIN__
   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: 
   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: 
   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:       {
  101:         handler_t old_handler = SIGPIPE_handler;
  102:         SIGPIPE_handler = handler;
  103:         return old_handler;
  104:       }
  105:     default: /* System defined signal */
  106:       return signal (sig, handler);
  107:     }
  108: }
  109: # undef signal
  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)
  120:         sig = SIGABRT;
  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)
  143:         sig = SIGABRT;
  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)
  163:         sig = SIGABRT;
  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)
  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:         }
  248:       to_unblock = blocked_set & ~new_blocked_set;
  249:       to_block = new_blocked_set & ~blocked_set;
  250: 
  251:       if (to_block != 0)
  252:         {
  253:           int sig;
  254: 
  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:         }
  263: 
  264:       if (to_unblock != 0)
  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:         }
  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)
  304:         sig = SIGABRT;
  305:       #endif
  306: 
  307:       if (blocked_set & (1U << sig))
  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:         }
  322:       else
  323:         return signal (sig, handler);
  324:     }
  325:   else
  326:     {
  327:       errno = EINVAL;
  328:       return SIG_ERR;
  329:     }
  330: }
  331: 
  332: #if GNULIB_defined_SIGPIPE
  333: /* Raise the signal SIGPIPE.  */
  334: int
  335: _gl_raise_SIGPIPE (void)
  336: {
  337:   if (blocked_set & (1U << SIGPIPE))
  338:     pending_array[SIGPIPE] = 1;
  339:   else
  340:     {
  341:       handler_t handler = SIGPIPE_handler;
  342:       if (handler == SIG_DFL)
  343:         exit (128 + SIGPIPE);
  344:       else if (handler != SIG_IGN)
  345:         (*handler) (SIGPIPE);
  346:     }
  347:   return 0;
  348: }
  349: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>