1
/* POSIX compatible signal blocking.
2
Copyright (C) 2008-2011 Free Software Foundation, Inc.
3
Written by Eric Blake <ebb9@byu.net>, 2008.
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.
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.
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/>. */
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.
39
- We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
41
- We don't implement SA_ONSTACK, because sigaltstack() is not present.
42
- We ignore SA_RESTART, because blocking Win32 calls are not interrupted
43
anyway when an asynchronous signal occurs, and the MSVCRT runtime
44
never sets errno to EINTR.
45
- We don't implement SA_SIGINFO because it is impossible to do so
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(). */
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"
58
/* Out-of-range substitutes make a good fallback for uncatchable
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
75
/* A signal handler. */
76
typedef void (*handler_t) (int signal);
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 */;
82
/* Signal handler that is installed for signals. */
84
sigaction_handler (int sig)
89
int saved_errno = errno;
90
if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
92
/* Unexpected situation; be careful to avoid recursive abort. */
94
signal (SIGABRT, SIG_DFL);
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
106
handler = action_array[sig].sa_handler;
107
if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
108
signal (sig, sigaction_handler);
110
action_array[sig].sa_handler = NULL;
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);
118
/* Invoke the user's handler, then restore prior mask. */
122
sigprocmask (SIG_SETMASK, &oldmask, NULL);
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. */
131
sigaction (int sig, const struct sigaction *restrict act,
132
struct sigaction *restrict oact)
138
if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
139
|| (act && act->sa_handler == SIG_ERR))
145
#ifdef SIGABRT_COMPAT
146
if (sig == SIGABRT_COMPAT)
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. */
161
sigprocmask (SIG_BLOCK, &mask, &oldmask);
164
if (action_array[sig].sa_handler)
165
*oact = action_array[sig];
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)
173
signal (sig, oact->sa_handler);
174
oact->sa_flags = SA_RESETHAND | SA_NODEFER;
175
sigemptyset (&oact->sa_mask);
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)
185
if (signal (sig, act->sa_handler) == SIG_ERR)
187
action_array[sig].sa_handler = NULL;
191
if (signal (sig, sigaction_handler) == SIG_ERR)
193
action_array[sig] = *act;
196
sigprocmask (SIG_SETMASK, &oldmask, NULL);
201
sigprocmask (SIG_SETMASK, &oldmask, NULL);