A signal handler should not re-assert reassert its desire to handle its own signal. This is often done on non-persistent platforms, that is, when a signal handler receives a signal that is bound to a handler, these platforms unbind the signal to default behavior before calling the handler.
A signal handler may only call signal()
if it does not need to be asyncasynchronous-safe (in other words, all relevant signals are masked, and therefore it may therefore not be interrupted.)
Non-Compliant Code Example
...
POSIX defines the sigaction(2)
function, which assigns handlers to signals like signal(2)
, but also allows one you to explicitly set persistence. One So you can thus use sigaction(2)
and sidestep the race window on non-persistent OS'sOSs.
Code Block | ||
---|---|---|
| ||
void handler(int signum) { /* Handle Signal */ } /* ... */ /* Equivalent to signal( signum, handler); but make signal persistent */ struct sigaction act; act.sa_handler = handler; act.sa_flags = 0; if (sigemptyset( &act.sa_mask) != 0) { /* Handle Error */ } if (sigaction(signum, &act, NULL) != 0) { /* Handle Error */ } |
While the handler in this example does not call signal()
, it safely can , since because the signal is masked and so the handler can not cannot be interrupted. Note that if the same handler is installed for more than one signal number, it would be necessary to mask the signals explicitly in act.sa_mask
in order to ensure that the handler can not cannot be interrupted, since because the system only masks the signal being delivered.
POSIX recommends sigaction(2)
and deprecates signal(2)
. Unfortunately, sigaction(2)
is not C99-compliant , and is not supported on some platforms, including Windows.
...
SIG34-EX1: On a machine with persistent signal handlers, it is safe for a handler to modify the behavior for its own signal. This would include having the signal be ignored, reset to default behavior, or handled by a different handler. A handler assigning itself to its own signal is also safe, as it is a no-op. The handler is impervious to a race condition since because multiple invocations of its signal will merely cause it to '"interrupt itself', " until it manages to reassign its signal.
...
Not all systems have persistent signal handlers. For more info, see SIG01-A. Understand implementation-specific details regarding signal handler persistence.
Risk Assessment
Two signals in quick succession can trigger the race condition on non-persistent platforms, causing the signal's default behavior despite a handler's attempt to override it.
...