Exceptional Control Flow(6)

A signal that has been sent but not yet received is called a pending signal.

At any point in time, there can be at most one pending signal of a particular type.

If a process has a pending signal of type k, then any subsequent signals of type k sent to that process are not queued; they are simply discarded.

A process can selectively block the receipt of certain signals.

When a signal is blocked, it can be delivered, but the resulting pending signal will not be received until the process unblocks the signal. 

A pending signal is received at most once.  

For each process, the kernel main- tains the set of pending signals in the pending bit vector,  and the set of blocked signals in the blocked bit vector.  

The kernel sets bit k in pending whenever a sig- nal of type k is delivered and clears bit k in pending whenever a signal of type k is received

Sending Signals 

Unix systems provide a number of mechanisms for sending signals to processes. All of the mechanisms rely on the notion of a process group

Process Groups 

Every process belongs to exactly one process group, which is identified by a positive integer process group ID.

The getpgrp function returns the process group ID of the current process. 

By default, a child process belongs to the same process group as its parent.

A process can change the process group of itself or another process by using the setpgid function: 

The setpgid function changes the process group of process pid to pgid.

If pid is zero, the PID of the current process is used. 

If pgid is zero, the PID of the process specified by pid is used for the process group ID.  

For example, if process 15213 is the calling process, then 

setpgid(0, 0);

creates a new process group whose process group ID is 15213, and adds process 15213 to this new group. 

Sending Signals with the /bin/kill Program

The /bin/kill program sends an arbitrary signal to another process. For example, the command 

sends signal 9 (SIGKILL) to process 15213.  

unix> /bin/kill -9 15213

A negative PID causes the signal to be sent to every process in process group PID.  

Sending Signals from the Keyboard 

Unix shells use the abstraction of a job to represent the processes that are created as a result of evaluating a single command line

At any point in time, there is at most one foreground job and zero or more background jobs.  

The shell creates a separate process group for each job

Typically, the process group ID is taken from one of the parent processes in the job.  

Figure 8.27 shows a shell with one foreground job and two background jobs.

The parent process in the foreground job has a PID of 20 and a process group ID of 20.

The parent process has created two children, each of which are also members of process group 20

Typing ctrl-c at the keyboard causes a SIGINT signal to be sent to the shell.

The shell catches the signal (see Section 8.5.3) and then sends a SIGINT to every process in the foreground process group

Sending Signals with the kill Function

Processes send signals to other processes (including themselves) by calling the kill function. 

If pid is greater than zero, then the kill function sends signal number sig to process pid.

If pid is less than zero, then kill sends signal sig to every process in process group abs(pid). 

Sending Signals with the alarm Function

A process can send SIGALRM signals to itself by calling the alarm function. 

The alarm function arranges for the kernel to send a SIGALRM signal to the calling process in secs seconds. 

Receiving Signals 

When the kernel is returning from an exception handler and is ready to pass control to process p, it checks the set of unblocked pending signals

(pending & ~blocked) for process p. If this set is empty (the usual case), then the kernel passes control to the next instruction (Inext) in the logical control flow of p. 

However, if the set is nonempty, then the kernel chooses some signal k in the set (typically the smallest k) and forces p to receive signal k.

The receipt of the signal triggers some action by the process.

Once the process completes the action, then control passes back to the next instruction (Inext ) in the logical control flow of p.

Each signal type has a predefined default action, which is one of the following: 

(1) The process terminates

(2) The process terminates and dumps core

(3) The process stops until restarted by a SIGCONT signal. 

(4) The process ignores the signal. 

A process can modify the default action associated with a signal by using the signal function:

The signal function can change the action associated with a signal signum in one of three ways: 

(1) If handler is SIG_IGN, then signals of type signum are ignored

(2) If handler is SIG_DFL, then the action for signals of type signum reverts to the default action. 

(3) Otherwise, handler is the address of a user-defined function, called a signal handler, that will be called whenever the process receives a signal of type signum.  

When a process catches a signal of type k, the handler installed for signal k is invoked with a single integer argument set to k.

This argument allows the same handler function to catch different types of signals

Signal handlers are yet another example of concurrency in a computer system.

The execution of the signal handler interrupts the execution of the main C routine, akin to the way that a low-level exception handler interrupts the control flow of the current application program.

Since the logical control flow of the signal handler overlaps the logical control flow of the main routine, the signal handler and the main routine run concurrently

Signal Handling Issues 

...However, subtle issues arise when a program catches multiple signals. 

(1) Pending signals are blocked. Unix signal handlers typically block pending signals of the type currently being processed by the handler.  

For example, suppose a process has caught a SIGINT signal and is currently running its SIGINT handler.

If another SIGINT signal is sent to the process, then the SIGINT will become pending, but will not be received until after the handler returns. 

(2) Pending signals are not queued. There can be at most one pending signal of any particular type.

Thus, if two signals of type k are sent to a destination process while signal k is blocked because the destination process is currently executing a handler for signal k,

then the second signal is simply discarded; it is not queued. The key idea is that the existence of a pending signal merely indicates that at least one signal has arrived

(3) System calls can be interrupted. System calls such as read, wait, and accept that can potentially block the process for a long period of time are called slow system calls.

On some systems, slow system calls that are interrupted when a handler catches a signal do not resume when the signal handler returns,

but instead return immediately to the user with an error condition and errno set to EINTR

原文地址:https://www.cnblogs.com/geeklove01/p/9264938.html