Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

A signal handler should not reassert its desire to handle its own signal. This is often done on nonpersistent platforms—that is, platforms that, upon receiving a signal, reset the disposition handler for the signal to a default value before calling the bound signal handler. Calling signal() under these conditions presents a race condition . See (see SIG01-C. Understand implementation-specific details regarding signal handler persistence).

A signal handler may call signal() only if it does not need to be asynchronous-safe. (In other wordsthat is, if all relevant signals are masked so that the handler cannot be interrupted).)

Noncompliant Code Example (POSIX)

On nonpersistent platforms, this noncompliant code example 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, consequently defeating the persistent behavior implied by the call to signal() from within the handler to reassert the binding.

...

Code Block
bgColor#ffcccc
langc
#include <signal.h>
 
void handler(int signum) {
  if (signal(signum, handler) == SIG_ERR) {
    /* Handle error */
  }
  /* Handle signal */
}
 
void func(void) {
  if (signal(SIGUSR1, handler) == SIG_ERR) {
    /* Handle error */
  }
}

Compliant Solution

...

(POSIX)

Calling For persistent platforms, calling the signal() function from within the signal handler to reassert the binding is unnecessary for persistent platforms, as in this compliant solution:

Code Block
bgColor#ccccff
langc
#include <signal.h>
 
void handler(int signum) {
  /* Handle signal */
}
 
void func(void) {
  if (signal(SIGUSR1, handler) == SIG_ERR) {
    /* Handle error */
  }
}

Compliant Solution (POSIX)

POSIX defines the sigaction() function, which assigns handlers to signals in a similar manner to signal() but allows the caller to explicitly set persistence. Consequently, the sigaction() function can be used to eliminate the race window on nonpersistent operating systems.platforms, as in this compliant solution:

Code Block
bgColor#ccccff
langc
#include <signal.h>
 
void handler(int signum) {
  /* Handle signal */
}

void func(void) {
  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 */
  }
}

Although the handler in this example does not call signal(), it could do so safely because the signal is masked and the handler cannot be interrupted. If the same handler is installed for more than one signal number, the signals must be masked explicitly in act.sa_mask to ensure that the handler cannot be interrupted because the system masks only the signal being delivered.

POSIX recommends that new applications should use sigaction() and deprecates rather than signal(). Unfortunately, The sigaction() function is not defined by the C Standard and is not supported on some platforms, including Windows.

Compliant Solution (Windows)

There are two classes of signals in the Visual C++ implementation:

  • SIGSEGV, SIGILL, and SIGFPE have per-thread handlers, so each thread may register its own handler for these signals.
  • SIGABRT, SIGBREAK, SIGTERM, and SIGINT have global handlers and access to these handlers is synchronized via a global lock.

For the signals with global handlers, the handler is reset to SIG_DFL and the handler is called under a lock, so there is no race if signal() is called again from the handler to reassert itself as the handler. For the signals with per-thread handlers, the state is local to the thread and resultantly there is no opportunity for a race is no safe way to implement persistent signal-handler behavior on Windows platforms, and it should not be attempted. If a design depends on this behavior, and the design cannot be altered, it may be necessary to claim a deviation from this rule after completing an appropriate risk analysis.

Exceptions

SIG34-EX1: For implementations with persistent signal handlers, it is safe for a handler to modify the behavior of its own signal. Behavior modifications include ignoring the signal, resetting to the default behavior, or and having the signal handled by a different handler. A handler reasserting it's its binding is also safe but unnecessary.

...

 

...