13.13 <csignal>

The <csignal> header is the C++ version of the standard C <signal.h> header. It declares functions and macros related to signal handling.

A signal is a condition that can arise during program execution. A signal can originate by an explicit call to raise or abort, from external sources (such as the user interrupting the program), or from internal events (such as floating-point errors or memory violations). Each signal has a handler, which is a function that the C++ library calls when a signal occurs (called raising the signal).

figs/acorn.gif

Signals are identified by integers. A program can establish different handlers for different signal numbers. You can choose to ignore a signal by using SIG_IGN as the signal handler. If the signal is raised, no handler is called, and the program continues. Each signal also has a default handler (SIG_DFL). When a program starts, every signal number is initialized with SIG_IGN or SIG_DFL. The details are implementation-defined.

You can set your own handler for any signal by calling the signal function. A handler is a function that takes one parameter: the signal number. The signal handler function is limited in what it can do. Unless a signal is raised by an explicit call to raise or abort, the only useful thing the handler can do is to set a global flag. The type of the flag must be sig_atomic_t.

The standard defines a basic set of signals, and an implementation is free to define additional signals. On the other hand, an implementation is not required to raise any signals. Remember that arithmetic overflow, pointer violations, and the like result in undefined behavior. (See Chapter 4.) Thus, an implementation is free to terminate a program immediately, ignore the error, raise a signal, or do anything else. Some signals are meant to reflect external events, such as the user terminating the program. How the user terminates a program is likewise implementation-defined.

Unix and Unix-like operating systems have much more extensive signal-handling facilities. The <csignal> handler as documented in this section is portable to all hosted C++ environments, regardless of operating system, although the portable behavior is limited. Most uses of <csignal> in real programs take advantage of additional, nonstandard capabilities. Consult your compiler's and library's documentation for details.

raise function Raises a signal

int raise(int sig);

The raise function sends a signal to the running program. The sig parameter is the signal number. The return value is 0 for success or nonzero for an error.

SIG_DFL macro Default handler

void (*SIG_DFL)(int)

The SIG_DFL macro represents the default handling of a signal. The macro expands to a constant whose value is suitable as the second argument to the signal function.

SIG_ERR macro Error return

void (*SIG_ERR)(int)

The SIG_ERR macro represents the value returned from signal in the event of an error. It expands to a constant expression.

SIG_IGN macro Ignore signal

void (*SIG_IGN)(int)

The SIG_IGN macro tells signal to ignore a signal. The macro expands to a constant whose value is suitable as the second argument to the signal function.

SIGABRT macro Abort signal number

int SIGABRT

The SIGABRT macro expands to a positive integer constant that represents an abnormal termination. The abort function raises SIGABRT.

SIGFPE macro Floating-point error signal number

int SIGFPE

The SIGFPE macro expands to a positive integer constant that represents a floating-point exception, such as division by zero. An implementation is not required to raise SIGFPE for a floating-point error.

SIGILL macro Illegal instruction signal number

int SIGILL

The SIGILL macro expands to a positive integer constant that represents an illegal instruction.

SIGINT macro User interrupt signal number

int SIGINT

The SIGINT macro expands to a positive integer constant that represents a user interrupt.

SIGSEGV macro Segmentation violation signal number

int SIGSEGV

The SIGSEGV macro expands to a positive integer constant that represents an addressing fault (segmentation violation).

SIGTERM macro Terminate signal number

int SIGTERM

Description

The SIGTERM macro expands to a positive integer constant that represents a request to terminate the program.

sig_atomic_t type Atomic type

typedef ... sig_atomic_t;

figs/acorn.gif

The sig_atomic_t type is an integral type that can be accessed atomicallythat is, even if a signal is delivered, the entire value is read or written. The actual type is implementation-defined.

signal function Sets a signal handler

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

The signal function controls the program's behavior when a signal is delivered to the program. The first parameter (sig) is the signal number. The second parameter (func) is the function to call when signal sig is delivered.

The func parameter can also be one of the special values SIG_DFL or SIG_IGN. Use SIG_DFL to get the default behavior; use SIG_IGN to ignore a signal.

figs/acorn.gif

The default behavior for a signal is implementation-defined, but it usually results in the termination of the program. The signal handler must not use any C++ features (such as throwing an exception), or the results will be implementation-defined. The function must have "C" linkage.

If the func parameter is a function pointer, that function is called when signal sig is delivered. Unless the signal is delivered by calling abort or raise, the function is highly restricted in what it can do:

  • The handler must not call any function in the standard library except signal, and the first parameter must be sig.

  • The handler must not refer to any variable with static storage except it can assign a value to a variable of type volatile sig_atomic_t.

  • If the signal is the result of a computational error such as SIGFPE, the signal handler must not return, but should call abort or exit. (Yes, this item contradicts the first item.)

Real implementations have looser restrictions, such as allowing calls to other library functions from a signal handler. The library functions that are permitted varies, but every practical implementation allows at least abort. If you must use signal handlers in your program, you will probably need to rely on behavior that is dictated by your host environment, extending the limitations of the C++ standard.

If the handler returns normally, and the signal is not the result of a computational error, execution continues from the point where it was interrupted.

The return value of signal is the previous value of the signal handler for sig, or SIG_ERR for an error. If SIG_ERR is returned, errno is set.

Example 13-7 shows a simple signal handler that sets a global flag when the user interrupts the program. Until the user interrupts it, the program reads input and counts the number of lines the user typed.

Example

Example 13-7. Reading input until the program is interrupted
#include <csignal>

#include <iostream>

#include <string>

   

volatile std::sig_atomic_t interrupted;

   

// Signal handler sets a global flag

extern "C" void sigint(int sig)

{

  interrupted = 1;

}

   

int main(  )

{

  //

  if (std::signal(SIGINT, sigint) == SIG_ERR)

    std::cerr << "Cannot set signal handler\n";

  else

  {

    unsigned long count = 0;           // Count lines.

    while(! interrupted)

    {

      std::cout << "> ";               // User prompt

      std::string s;

      if (! std::getline(std::cin, s))

        // EOF does not terminate the loop; only SIGINT does this.

        std::cin.clear(  );

      ++count;

    }

    std::cout << "I counted " << count << " line(s).\n";

  }

}