9b0c92fdae8f74683bfa2c3538f68f62c3726d6f
[pspp] / lib / sigaction.c
1 /* POSIX compatible signal blocking.
2    Copyright (C) 2008 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 Woe32 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, SIGCHLD is not defined, so we don't implement
39    SA_NOCLDSTOP or SA_NOCLDWAIT; sigaltstack() is not present, so we
40    don't implement SA_ONSTACK; and siginterrupt() is not present, so
41    we don't implement SA_RESTART.  Supporting SA_SIGINFO is impossible
42    to do portably.
43
44    POSIX states that an application should not mix signal() and
45    sigaction().  We support the use of signal() within the gnulib
46    sigprocmask() substitute, but all other application code linked
47    with this module should stick with only sigaction().  */
48
49 /* Check some of our assumptions.  */
50 #if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
51 # error "Revisit the assumptions made in the sigaction module"
52 #endif
53
54 /* Out-of-range substitutes make a good fallback for uncatchable
55    signals.  */
56 #ifndef SIGKILL
57 # define SIGKILL (-1)
58 #endif
59 #ifndef SIGSTOP
60 # define SIGSTOP (-1)
61 #endif
62
63 /* A signal handler.  */
64 typedef void (*handler_t) (int signal);
65
66 /* Set of current actions.  If sa_handler for an entry is NULL, then
67    that signal is not currently handled by the sigaction handler.  */
68 static struct sigaction volatile action_array[NSIG] /* = 0 */;
69
70 /* Signal handler that is installed for signals.  */
71 static void
72 sigaction_handler (int sig)
73 {
74   handler_t handler;
75   sigset_t mask;
76   sigset_t oldmask;
77   int saved_errno = errno;
78   if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
79     {
80       /* Unexpected situation; be careful to avoid recursive abort.  */
81       if (sig == SIGABRT)
82         signal (SIGABRT, SIG_DFL);
83       abort ();
84     }
85
86   /* Reinstall the signal handler when required; otherwise update the
87      bookkeeping so that the user's handler may call sigaction and get
88      accurate results.  We know the signal isn't currently blocked, or
89      we wouldn't be in its handler, therefore we know that we are not
90      interrupting a sigaction() call.  There is a race where any
91      asynchronous instance of the same signal occurring before we
92      reinstall the handler will trigger the default handler; oh
93      well.  */
94   handler = action_array[sig].sa_handler;
95   if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
96     signal (sig, sigaction_handler);
97   else
98     action_array[sig].sa_handler = NULL;
99
100   /* Block appropriate signals.  */
101   mask = action_array[sig].sa_mask;
102   if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
103     sigaddset (&mask, sig);
104   sigprocmask (SIG_BLOCK, &mask, &oldmask);
105
106   /* Invoke the user's handler, then restore prior mask.  */
107   errno = saved_errno;
108   handler (sig);
109   saved_errno = errno;
110   sigprocmask (SIG_SETMASK, &oldmask, NULL);
111   errno = saved_errno;
112 }
113
114 /* Change and/or query the action that will be taken on delivery of
115    signal SIG.  If not NULL, ACT describes the new behavior.  If not
116    NULL, OACT is set to the prior behavior.  Return 0 on success, or
117    set errno and return -1 on failure.  */
118 int
119 sigaction (int sig, const struct sigaction *restrict act,
120            struct sigaction *restrict oact)
121 {
122   sigset_t mask;
123   sigset_t oldmask;
124   int saved_errno;
125
126   if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
127       || (act && act->sa_handler == SIG_ERR))
128     {
129       errno = EINVAL;
130       return -1;
131     }
132
133   /* POSIX requires sigaction() to be async-signal-safe.  In other
134      words, if an asynchronous signal can occur while we are anywhere
135      inside this function, the user's handler could then call
136      sigaction() recursively and expect consistent results.  We meet
137      this rule by using sigprocmask to block all signals before
138      modifying any data structure that could be read from a signal
139      handler; this works since we know that the gnulib sigprocmask
140      replacement does not try to use sigaction() from its handler.  */
141   if (!act && !oact)
142     return 0;
143   sigfillset (&mask);
144   sigprocmask (SIG_BLOCK, &mask, &oldmask);
145   if (oact)
146     {
147       if (action_array[sig].sa_handler)
148         *oact = action_array[sig];
149       else
150         {
151           /* Safe to change the handler at will here, since all
152              signals are currently blocked.  */
153           oact->sa_handler = signal (sig, SIG_DFL);
154           if (oact->sa_handler == SIG_ERR)
155             goto failure;
156           signal (sig, oact->sa_handler);
157           oact->sa_flags = SA_RESETHAND | SA_NODEFER;
158           sigemptyset (&oact->sa_mask);
159         }
160     }
161
162   if (act)
163     {
164       /* Safe to install the handler before updating action_array,
165          since all signals are currently blocked.  */
166       if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
167         {
168           if (signal (sig, act->sa_handler) == SIG_ERR)
169             goto failure;
170           action_array[sig].sa_handler = NULL;
171         }
172       else
173         {
174           if (signal (sig, sigaction_handler) == SIG_ERR)
175             goto failure;
176           action_array[sig] = *act;
177         }
178     }
179   sigprocmask (SIG_SETMASK, &oldmask, NULL);
180   return 0;
181
182  failure:
183   saved_errno = errno;
184   sigprocmask (SIG_SETMASK, &oldmask, NULL);
185   errno = saved_errno;
186   return -1;
187 }