Home | History | Annotate | Download | only in lib
      1 /* POSIX compatible signal blocking.
      2    Copyright (C) 2008-2012 Free Software Foundation, Inc.
      3    Written by Eric Blake <ebb9 (at) byu.net>, 2008.
      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 /* This implementation of sigaction is tailored to native Windows behavior:
     28    signal() has SysV semantics (ie. the handler is uninstalled before
     29    it is invoked).  This is an inherent data race if an asynchronous
     30    signal is sent twice in a row before we can reinstall our handler,
     31    but there's nothing we can do about it.  Meanwhile, sigprocmask()
     32    is not present, and while we can use the gnulib replacement to
     33    provide critical sections, it too suffers from potential data races
     34    in the face of an ill-timed asynchronous signal.  And we compound
     35    the situation by reading static storage in a signal handler, which
     36    POSIX warns is not generically async-signal-safe.  Oh well.
     37 
     38    Additionally:
     39      - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
     40        is not defined.
     41      - We don't implement SA_ONSTACK, because sigaltstack() is not present.
     42      - We ignore SA_RESTART, because blocking native Windows API calls are
     43        not interrupted anyway when an asynchronous signal occurs, and the
     44        MSVCRT runtime never sets errno to EINTR.
     45      - We don't implement SA_SIGINFO because it is impossible to do so
     46        portably.
     47 
     48    POSIX states that an application should not mix signal() and
     49    sigaction().  We support the use of signal() within the gnulib
     50    sigprocmask() substitute, but all other application code linked
     51    with this module should stick with only sigaction().  */
     52 
     53 /* Check some of our assumptions.  */
     54 #if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
     55 # error "Revisit the assumptions made in the sigaction module"
     56 #endif
     57 
     58 /* Out-of-range substitutes make a good fallback for uncatchable
     59    signals.  */
     60 #ifndef SIGKILL
     61 # define SIGKILL (-1)
     62 #endif
     63 #ifndef SIGSTOP
     64 # define SIGSTOP (-1)
     65 #endif
     66 
     67 /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
     68    for the signal SIGABRT.  Only one signal handler is stored for both
     69    SIGABRT and SIGABRT_COMPAT.  SIGABRT_COMPAT is not a signal of its own.  */
     70 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
     71 # undef SIGABRT_COMPAT
     72 # define SIGABRT_COMPAT 6
     73 #endif
     74 
     75 /* A signal handler.  */
     76 typedef void (*handler_t) (int signal);
     77 
     78 /* Set of current actions.  If sa_handler for an entry is NULL, then
     79    that signal is not currently handled by the sigaction handler.  */
     80 static struct sigaction volatile action_array[NSIG] /* = 0 */;
     81 
     82 /* Signal handler that is installed for signals.  */
     83 static void
     84 sigaction_handler (int sig)
     85 {
     86   handler_t handler;
     87   sigset_t mask;
     88   sigset_t oldmask;
     89   int saved_errno = errno;
     90   if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
     91     {
     92       /* Unexpected situation; be careful to avoid recursive abort.  */
     93       if (sig == SIGABRT)
     94         signal (SIGABRT, SIG_DFL);
     95       abort ();
     96     }
     97 
     98   /* Reinstall the signal handler when required; otherwise update the
     99      bookkeeping so that the user's handler may call sigaction and get
    100      accurate results.  We know the signal isn't currently blocked, or
    101      we wouldn't be in its handler, therefore we know that we are not
    102      interrupting a sigaction() call.  There is a race where any
    103      asynchronous instance of the same signal occurring before we
    104      reinstall the handler will trigger the default handler; oh
    105      well.  */
    106   handler = action_array[sig].sa_handler;
    107   if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
    108     signal (sig, sigaction_handler);
    109   else
    110     action_array[sig].sa_handler = NULL;
    111 
    112   /* Block appropriate signals.  */
    113   mask = action_array[sig].sa_mask;
    114   if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
    115     sigaddset (&mask, sig);
    116   sigprocmask (SIG_BLOCK, &mask, &oldmask);
    117 
    118   /* Invoke the user's handler, then restore prior mask.  */
    119   errno = saved_errno;
    120   handler (sig);
    121   saved_errno = errno;
    122   sigprocmask (SIG_SETMASK, &oldmask, NULL);
    123   errno = saved_errno;
    124 }
    125 
    126 /* Change and/or query the action that will be taken on delivery of
    127    signal SIG.  If not NULL, ACT describes the new behavior.  If not
    128    NULL, OACT is set to the prior behavior.  Return 0 on success, or
    129    set errno and return -1 on failure.  */
    130 int
    131 sigaction (int sig, const struct sigaction *restrict act,
    132            struct sigaction *restrict oact)
    133 {
    134   sigset_t mask;
    135   sigset_t oldmask;
    136   int saved_errno;
    137 
    138   if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
    139       || (act && act->sa_handler == SIG_ERR))
    140     {
    141       errno = EINVAL;
    142       return -1;
    143     }
    144 
    145 #ifdef SIGABRT_COMPAT
    146   if (sig == SIGABRT_COMPAT)
    147     sig = SIGABRT;
    148 #endif
    149 
    150   /* POSIX requires sigaction() to be async-signal-safe.  In other
    151      words, if an asynchronous signal can occur while we are anywhere
    152      inside this function, the user's handler could then call
    153      sigaction() recursively and expect consistent results.  We meet
    154      this rule by using sigprocmask to block all signals before
    155      modifying any data structure that could be read from a signal
    156      handler; this works since we know that the gnulib sigprocmask
    157      replacement does not try to use sigaction() from its handler.  */
    158   if (!act && !oact)
    159     return 0;
    160   sigfillset (&mask);
    161   sigprocmask (SIG_BLOCK, &mask, &oldmask);
    162   if (oact)
    163     {
    164       if (action_array[sig].sa_handler)
    165         *oact = action_array[sig];
    166       else
    167         {
    168           /* Safe to change the handler at will here, since all
    169              signals are currently blocked.  */
    170           oact->sa_handler = signal (sig, SIG_DFL);
    171           if (oact->sa_handler == SIG_ERR)
    172             goto failure;
    173           signal (sig, oact->sa_handler);
    174           oact->sa_flags = SA_RESETHAND | SA_NODEFER;
    175           sigemptyset (&oact->sa_mask);
    176         }
    177     }
    178 
    179   if (act)
    180     {
    181       /* Safe to install the handler before updating action_array,
    182          since all signals are currently blocked.  */
    183       if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
    184         {
    185           if (signal (sig, act->sa_handler) == SIG_ERR)
    186             goto failure;
    187           action_array[sig].sa_handler = NULL;
    188         }
    189       else
    190         {
    191           if (signal (sig, sigaction_handler) == SIG_ERR)
    192             goto failure;
    193           action_array[sig] = *act;
    194         }
    195     }
    196   sigprocmask (SIG_SETMASK, &oldmask, NULL);
    197   return 0;
    198 
    199  failure:
    200   saved_errno = errno;
    201   sigprocmask (SIG_SETMASK, &oldmask, NULL);
    202   errno = saved_errno;
    203   return -1;
    204 }
    205