Versions Compared

Key

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

A signal is a mechanism for transferring control that is typically used to notify a process that an event has occurred. That process can then respond to that event accordingly. C99 provides  The C standard provides functions for sending and handling signals within a C program.

Processes handle signals by registering a signal handler using the signal() function, which is specified as

Code Block

void (*signal(int sig, void (*func)(int)))(int);

This is conceptually equivalent to

Code Block

typedef void (*sighandler_t)(int signum);
extern sighandler_t signal(
  int signum, 
  sighandler_t handler
);

...

This noncompliant code example registers a single signal handler to process both SIGUSR1 and SIGUSR2. The variable sig2 should be set to 1 if one or more SIGUSR1 signals are followed by SIGUSR2, essentially implementing a finite state machine within the signal handler.

Code Block
bgColor#FFcccc
langc

#include <signal.h>

volatile sig_atomic_t sig1 = 0;
volatile sig_atomic_t sig2 = 0;

void handler(int signum) {
  if (signum == SIGUSR1) {
    sig1 = 1;
  }
  else if (sig1) {
    sig2 = 1;
  }
}

int main(void) {
  if (signal(SIGUSR1, handler) == SIG_ERR) {
    /* Handle error */
  }
  if (signal(SIGUSR2, handler) == SIG_ERR) {
    /* Handler error */
  }

  while (sig2 == 0) {
    /* Do nothing or give up CPU for a while */
  }

  /* ... */

  return 0;
}

Unfortunately, there is a race condition occurs in the implementation of handler(). If handler() is called to handle SIGUSR1 and is interrupted to handle SIGUSR2, it is possible that sig2 will not be set.

...

The POSIX sigaction() function assigns handlers to signals in a similar manner to the C99 C signal() function, but it also allows signal masks to be set explicitly. Consequently, sigaction() can be used to prevent a signal handler from interrupting itself.

Code Block
bgColor#ccccff
langc

#include <signal.h>
#include <stdio.h>

volatile sig_atomic_t sig1 = 0;
volatile sig_atomic_t sig2 = 0;

void handler(int signum) {
  if (signum == SIGUSR1) {
    sig1 = 1;
  }
  else if (sig1) {
    sig2 = 1;
  }
}

int main(void) {
  struct sigaction act;
  act.sa_handler = &handler;
  act.sa_flags = 0;
  if (sigemptyset(&act.sa_mask) != 0) {
    /* Handle error */
  }
  if (sigaddset(&act.sa_mask, SIGUSR1)) {
    /* Handle error */
  }
  if (sigaddset(&act.sa_mask, SIGUSR2)) {
    /* Handle error */
  }

  if (sigaction(SIGUSR1, &act, NULL) != 0) {
    /* Handle error */
  }
  if (sigaction(SIGUSR2, &act, NULL) != 0) {
    /* Handle error */
  }

  while (sig2 == 0) {
    /* Do nothing or give up CPU for a while */
  }

  /* ... */

  return 0;
}

POSIX recommends sigaction() and deprecates signal(). Unfortunately, sigaction() is not defined in C99 and in the C standard and is consequently not as portable a solution.

...

CERT C++ Secure Coding Standard: CWE-662, "Insufficient Synchronizationsynchronization"

ISO/IEC 2003 Section 5.2.3, "Signals and interrupts"

...

[Dowd 2006] Chapter 13, "Synchronization and State" ("Signal Interruption interruption and Repetitionrepetition")
[Open Group 2004] longjmp
[OpenBSD] signal() Man Page
[Zalewski 2001]

...