Modern systems react to these situations by making abrupt changes in the control flow. In general, we refer to these abrupt changes as exceptional control flow(ECF). Exceptional control flow occurs at all levels of a computer system.
when the processor detects that the event has occurred, it makes an indirect procedure call (the exception), through a jump table called an exception table, to an operating system subroutine (the exception handler) that is specifically designed to process this particular kind of event.
When the exception handler finishes processing, one of three things happens, depending on the type of event that caused the exception:
1. The handler returns control to the current instruction Icurr , the instruction that was executing when the event occurred.
2. The handler returns control to Inext , the instruction that would have executed next had the exception not occurred.
3. The handler aborts the interrupted program.
The exception number is an index into the exception table, whose starting address is contained in a special CPU register called the exception table base register.
If control is being transferred from a user program to the kernel, all of these items are pushed onto the kernel’s stack rather than onto the user’s stack.
. Exception handlers run in kernel mode, which means they have complete access to all system resources.
There are up to 256 different exception types. Numbers in the range from 0 to 31 correspond to exceptions that are defined by the Intel architects, and thus are identical for any IA32 system. Numbers in the range from 32 to 255 correspond to interrupts and traps that are defined by the operating system.
a process is an instance of a program in execution.. An independent logical control flow that provides the illusion that our program has exclusive use of the processor.. Aprivate address space that provides the illusion that our program has exclusive use of the memory system.
A logical flow whose execution overlaps in time with another flow is called a concurrent flow, and the two flows are said to run concurrently. processes A and B run concurrently, as do A and C. On the other hand, B and C do not run concurrently. If two flows are running concurrently on different processor cores or computers, then we say that they are parallel flows, that they are running in parallel, and have parallel execution.
a mode bit in some control register that characterizes the privileges that the process currently enjoys. When the mode bit is set, the process is running in kernel mode (sometimes called supervisor mode).
The only way for the process to change from user mode to kernel mode is via an exception such as an interrupt, a fault, or a trapping system call.
a context switch that (1) saves the context of the current process, (2) restores the saved context of some previously preempted process, and (3) passes control to this newly restored process.
The newly created child process is almost, but not quite, identical to the parent. The child gets an identical (but separate) copy of the parent’s user-level virtual address space, including the text, data, and bss segments, heap, and user stack. The child also gets identical copies of any of the parent’s open file descriptors, which means the child can read and write any files that were open in the parent when it called fork. The most significant difference between the parent and the newly created child is that they have different PIDs.
In the parent, fork returns the PID of the child. In the child, fork returns a value of 0. Call once, return twice.
When a process terminates for any reason, the kernel does not remove it from the system immediately. Instead, the process is kept around in a terminated state until it is reaped by its parent. A terminated process that has not yet been reaped is called a zombie.
The execve function loads and runs the executable object file filename with the argument list argv and the environment variable list envp. Execve returns to the calling program only if there is an error such as not being able to find filename. So unlike fork, which is called once but returns twice, execve is called once and never returns.
A shell performs a sequence of read/evaluate steps, and then terminates. The read step reads a command line from the user. The evaluate step parses the command line and runs programs on behalf of the user.
A signal is a small message that notifies a process that an event of some type has occurred in the system.
. Sending a signal.The kernel sends (delivers) a signal to a destination process by updating some state in the context of the destination process. The signal is delivered for one of two reasons: (1) The kernel has detected a system event such as a divide-by-zero error or the termination of a child process. (2) A process has invoked the kill function (discussed in the next section) to explicitly request the kernel to send a signal to the destination process. A
process can send a signal to itself.
. Receiving a signal.A destination process receives a signal when it is forced by the kernel to react in some way to the delivery of the signal. The process can either ignore the signal, terminate, or catch the signal by executing a user-level function called a signal handler. Figure 8.26 shows the basic idea of a handler catching a signal.
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.
Notice that the program uses the signal function to install a signal handler function (handler) that is called asynchronously, interrupting the infinite while loop in main, whenever the process receives a SIGALRM signal. When the handler function returns, control passes back to main, which picks up where it was interrupted by the arrival of the signal.
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 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.
A process can modify the default action associated with a signal by using the signal function. The only exceptions are SIGSTOP and SIGKILL, whose default actions cannot be changed.
signals cannot be used to count the occurrence of events in other processes. Same type signal is allowed to pending once, no queue, so other coming signal is ignored.
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.
C provides a form of user-level exceptional control flow, called a nonlocal jump, that transfers control directly from one function to another currently executing function without having to go through the normal call-and-return sequence. Nonlocal jumps are provided by the setjmp and longjmp functions.
Linux systems provide a number of useful tools for monitoring and manipulating processes:
-strace: Prints a trace of each system call invoked by a running program and its children. A fascinating tool for the curious student. Compile your program with -static to get a cleaner trace without a lot of output related to shared libraries.
-ps: Lists processes (including zombies) currently in the system.
-top: Prints information about the resource usage of current processes.
-pmap: Displays the memory map of a process.
-/proc: A virtual filesystem that exports the contents of numerous kernel data structures in an ASCII text form that can be read by user programs. For example, type “cat /proc/loadavg” to see the current load average on your Linux system.