1 /* POSIX compatible signal blocking.
2 Copyright (C) 2008 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.
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
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(). */
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"
54 /* Out-of-range substitutes make a good fallback for uncatchable
63 /* A signal handler. */
64 typedef void (*handler_t) (int signal);
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 */;
70 /* Signal handler that is installed for signals. */
72 sigaction_handler (int sig)
77 int saved_errno = errno;
78 if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
80 /* Unexpected situation; be careful to avoid recursive abort. */
82 signal (SIGABRT, SIG_DFL);
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
94 handler = action_array[sig].sa_handler;
95 if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
96 signal (sig, sigaction_handler);
98 action_array[sig].sa_handler = NULL;
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);
106 /* Invoke the user's handler, then restore prior mask. */
110 sigprocmask (SIG_SETMASK, &oldmask, NULL);
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. */
119 sigaction (int sig, const struct sigaction *restrict act,
120 struct sigaction *restrict oact)
126 if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
127 || (act && act->sa_handler == SIG_ERR))
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. */
144 sigprocmask (SIG_BLOCK, &mask, &oldmask);
147 if (action_array[sig].sa_handler)
148 *oact = action_array[sig];
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)
156 signal (sig, oact->sa_handler);
157 oact->sa_flags = SA_RESETHAND | SA_NODEFER;
158 sigemptyset (&oact->sa_mask);
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)
168 if (signal (sig, act->sa_handler) == SIG_ERR)
170 action_array[sig].sa_handler = NULL;
174 if (signal (sig, sigaction_handler) == SIG_ERR)
176 action_array[sig] = *act;
179 sigprocmask (SIG_SETMASK, &oldmask, NULL);
184 sigprocmask (SIG_SETMASK, &oldmask, NULL);