root/maint/gnulib/lib/sigaction.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sigaction_handler
  2. sigaction

   1 /* POSIX compatible signal blocking.
   2    Copyright (C) 2008-2021 Free Software Foundation, Inc.
   3    Written by Eric Blake <ebb9@byu.net>, 2008.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file 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 Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser 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 /* 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 __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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */