• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* POSIX compatible signal blocking.
2    Copyright (C) 2008-2012 Free Software Foundation, Inc.
3    Written by Eric Blake <ebb9@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
sigaction_handler(int sig)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
sigaction(int sig,const struct sigaction * restrict act,struct sigaction * restrict oact)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