A signal is a software interrupt delivered to a process. The operating system uses signals to report exceptional situations to an executing program. Some signals report errors such as references to invalid memory addresses; others report asynchronous events, such as disconnection of a phone line.
The GNU C library defines a variety of signal types, each for a particular kind of event. Some kinds of events make it inadvisable or impossible for the program to proceed as usual, and the corresponding signals normally abort the program. Other kinds of signals that report harmless events are ignored by default.
If you anticipate an event that causes signals, you can define a handler function and tell the operating system to run it when that particular type of signal arrives.
Finally, one process can send a signal to another process; this allows a parent process to abort a child, or two related processes to communicate and synchronize.
This section explains basic concepts of how signals are generated, what happens after a signal is delivered, and how programs can handle signals.
A signal reports the occurrence of an exceptional event. These are some of the events that can cause (or generate, or raise) a signal:
A program error such as dividing by zero or issuing an address outside the valid range.
A user request to interrupt or terminate the program. Most environments are set up to let a user suspend the program by typing C-z, or terminate it with C-c. Whatever key sequence is used, the operating system sends the proper signal to interrupt the process.
The termination of a child process.
Expiration of a timer or alarm.
A call to kill or raise by the same process.
A call to kill from another process. Signals are a limited but useful form of interprocess communication.
An attempt to perform an I/O operation that cannot be done. Examples are reading from a pipe that has no writer (Chapter 16), and reading or writing to a terminal in certain situations (Chapter 28).
Each of these kinds of events (excepting explicit calls to kill and raise) generates its own particular kind of signal. The various kinds of signals are listed and described in detail in the section called “Standard Signals”.
In general, the events that generate signals fall into three major categories: errors, external events, and explicit requests.
An error means that a program has done something invalid and cannot continue execution. But not all kinds of errors generate signals--in fact, most do not. For example, opening a nonexistent file is an error, but it does not raise a signal; instead, open returns -1. In general, errors that are necessarily associated with certain library functions are reported by returning a value that indicates an error. The errors which raise signals are those which can happen anywhere in the program, not just in library calls. These include division by zero and invalid memory addresses.
An external event generally has to do with I/O or other processes. These include the arrival of input, the expiration of a timer, and the termination of a child process.
An explicit request means the use of a library function such as kill whose purpose is specifically to generate a signal.
Signals may be generated synchronously or asynchronously. A synchronous signal pertains to a specific action in the program, and is delivered (unless blocked) during that action. Most errors generate signals synchronously, and so do explicit requests by a process to generate a signal for that same process. On some machines, certain kinds of hardware errors (usually floating-point exceptions) are not reported completely synchronously, but may arrive a few instructions later.
Asynchronous signals are generated by events outside the control of the process that receives them. These signals arrive at unpredictable times during execution. External events generate signals asynchronously, and so do explicit requests that apply to some other process.
A given type of signal is either typically synchronous or typically asynchronous. For example, signals for errors are typically synchronous because errors generate signals synchronously. But any type of signal can be generated synchronously or asynchronously with an explicit request.
When a signal is generated, it becomes pending. Normally it remains pending for just a short period of time and then is delivered to the process that was signaled. However, if that kind of signal is currently blocked, it may remain pending indefinitely--until signals of that kind are unblocked. Once unblocked, it will be delivered immediately. the section called “Blocking Signals”.
When the signal is delivered, whether right away or after a long delay, the specified action for that signal is taken. For certain signals, such as SIGKILL and SIGSTOP, the action is fixed, but for most signals, the program has a choice: ignore the signal, specify a handler function, or accept the default action for that kind of signal. The program specifies its choice using functions such as signal or sigaction (the section called “Specifying Signal Actions”). We sometimes say that a handler catches the signal. While the handler is running, that particular signal is normally blocked.
If the specified action for a kind of signal is to ignore it, then any such signal which is generated is discarded immediately. This happens even if the signal is also blocked at the time. A signal discarded in this way will never be delivered, not even if the program subsequently specifies a different action for that kind of signal and then unblocks it.
If a signal arrives which the program has neither handled nor ignored, its default action takes place. Each kind of signal has its own default action, documented below (the section called “Standard Signals”). For most kinds of signals, the default action is to terminate the process. For certain kinds of signals that represent "harmless" events, the default action is to do nothing.
When a signal terminates a process, its parent process can determine the cause of termination by examining the termination status code reported by the wait or waitpid functions. (This is discussed in more detail in the section called “Process Completion”.) The information it can get includes the fact that termination was due to a signal and the kind of signal involved. If a program you run from a shell is terminated by a signal, the shell typically prints some kind of error message.
The signals that normally represent program errors have a special property: when one of these signals terminates the process, it also writes a core dump file which records the state of the process at the time of termination. You can examine the core dump with a debugger to investigate what caused the error.
If you raise a "program error" signal by explicit request, and this terminates the process, it makes a core dump file just as if the signal had been due directly to an error.