Signals are software interrupts. Most nontrivial application programs need to deal with signals. Signals provide a way of handling asynchronous events—for example, a user at a terminal typing the interrupt key to stop a program.

1 Signal Concepts

First, every signal has a name. These names all begin with the three characters SIG. For example, SIGABRT is the abort signal that is generated when a process calls the abort function. SIGALRM is the alarm signal that is generated when the timer set by the alarm function goes off.

Signal names are all defined by positive integer constants (the signal number) in the header <signal.h>.

Numerous conditions can generate a signal:

  • The terminal-generated signals occur when users press certain terminal keys. Pressing the Control-C key on the terminal normally causes the interrupt signal (SIGINT) to be generated. This is how to stop a runaway program.
  • Hardware exceptions generate signals: divide by 0, invalid memory reference, and the like. These conditions are usually detected by the hardware, and the kernel is notified. The kernel then generates the appropriate signal for the process that was running at the time the condition occurred. For example, SIGSEGV is generated for a process that executes an invalid memory reference.
  • The kill function allows a process to send any signal to another process or process group. Naturally, there are limitations: we have to be the owner of the process that we’re sending the signal to, or we have to be the superuser.
  • The kill command allows us to send signals to other processes. This command is often used to terminate a runaway background process.
  • Software conditions can generate signals when a process should be notified of various events.

Signals are classic examples of asynchronous events. They occur at what appear to be random times to the process. The process can’t simply test a variable (such as errno) to see whether a signal has occurred; instead, the process has to tell the kernel ‘‘if and when this signal occurs, do the following.’’

We can tell the kernel to do one of three things when a signal occurs. We call this the disposition of the signal, or the action associated with a signal.

  1. Ignore the signal.
  2. Catch the signal. To do this, we tell the kernel to call a function of ours whenever the signal occurs. In our function, we can do whatever we want to handle the condition.
  3. Let the default action apply. Every signal has a default action, shown in Figure 10.1. Note that the default action for most signals is to terminate the process.

When the default action is labeled ‘‘terminate+core,’’ it means that a memory image of the process is left in the file named core of the current working directory of the process. This file can be used with most UNIX System debuggers to examine the state of the process at the time it terminated.
core笔记

2 signal Function

1
void (*signal(int signo, void (*func)(int)))(int);

The signo argument is just the name of the signal from Figure 10.1. The value of func is (a) the constant SIG_IGN, (b) the constant SIG_DFL, or (c) the address of a function to be called when the signal occurs. If we specify SIG_IGN, we are telling the system to ignore the signal. (Remember that we cannot ignore the two signals SIGKILL and SIGSTOP.) When we specify SIG_DFL, we are setting the action associated with the signal to its default value. When we specify the address of a function to be called when the signal occurs, we are arranging to ‘‘catch’’ the signal. We call the function either the signal handler or the signal-catching function.

3 Unreliable Signals

Signals were unreliable. By this we mean that signals could get lost: a signal could occur and the process would never know about it.

4 Interrupted System Calls

5 Reentrant Functions

re-entrancy

6 Reliable-Signal Terminology and Semantics

First, a signal is generated for a process (or sent to a process) when the event that causes the signal occurs. The event could be a hardware exception (e.g., divide by 0), a software condition (e.g., an alarm timer expiring), a terminal-generated signal, or a call to the kill function. When the signal is generated, the kernel usually sets a flag of some form in the process table.

We say that a signal is delivered to a process when the action for a signal is taken. During the time between the generation of a signal and its delivery, the signal is said to be pending.

A process has the option of blocking the delivery of a signal. If a signal that is blocked is generated for a process, and if the action for that signal is either the default action or to catch the signal, then the signal remains pending for the process until the process either (a) unblocks the signal or (b) changes the action to ignore the signal. The system determines what to do with a blocked signal when the signal is delivered, not when it’s generated.This allows the process to change the action for the signal before it’s delivered. The sigpending function can be called by a process to determine which signals are blocked and pending.

Each process has a signal mask that defines the set of signals currently blocked from delivery to that process. We can think of this mask as having one bit for each possible signal. If the bit is on for a given signal, that signal is currently blocked.A process can examine and change its current signal mask by calling sigprocmask.

Since it is possible for the number of signals to exceed the number of bits in an integer, POSIX.1 defines a data type, called sigset_t, that holds a signal set. The signal mask, for example, is stored in one of these signal sets.

7 kill and raise Functions

The kill function sends a signal to a process or a group of processes. The raise function allows a process to send a signal to itself.

8 alarm and pause Functions

The alarm function allows us to set a timer that will expire at a specified time in the future. When the timer expires, the SIGALRM signal is generated. If we ignore or don’t catch this signal, its default action is to terminate the process.

The pause function suspends the calling process until a signal is caught.

9 Signal Sets

10 sigprocmask Function

11 sigpending Function

12 sigaction Function

The sigaction function allows us to examine or modify (or both) the action associated with a particular signal.

13 sigsetjmp and siglongjmp Functions

14 sigsuspend Function

15 abort Function

16 system Function

17 sleep, nanosleep, and clock_nanosleep Functions

18 sigqueue Function

19 Job-Control Signals

20 Signal Names and Numbers