A signal handler should not 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 platforms that, upon receiving a signal, unbind the signal to default behavior before calling the bound signal handler.
A signal handler may only call signal()
if it does not need to be asynchronous-safe (in other words, all relevant signals are masked, and consequently it may not be interrupted.)
Non-Compliant Code Example
In the following this non-compliant code example, the signal handler handler()
is bound to signum
.
Code Block | ||
---|---|---|
| ||
void handler(int signum) { signal(signum, handler); /* handle signal */ } /* ... */ signal(SIGUSR1, handler); |
Unfortunately On non-persistent platforms, this solution contains a race window, starting when the host environment resets the signal and ending when the handler calls signal()
. During that time, a second signal sent to the program will trigger the default signal behavior, thereby consequently defeating the persistent behavior implied by the call to signal()
from within the handler to reassert the binding.
...
Code Block | ||
---|---|---|
| ||
void handler(int signum) { /* handle signal */ } /* ... */ /* Equivalent to signal(SIGUSR1, 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(SIGUSR1, &act, NULL) != 0) { /* handle error */ } |
While the handler in this example does not call signal()
, it could safely can do so because the signal is masked and so consequently the handler cannot be interrupted. 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
to ensure that the handler cannot be interrupted, because the system only masks the signal being delivered.
...