Presentation is loading. Please wait.

Presentation is loading. Please wait.

Computer System Chapter 8. Exceptional Control Flow

Similar presentations


Presentation on theme: "Computer System Chapter 8. Exceptional Control Flow"— Presentation transcript:

1 Computer System Chapter 8. Exceptional Control Flow
Lynn Choi Korea University

2 Control Flow Computers do Only One Thing
From startup to shutdown, a CPU simply reads and executes (interprets) a sequence of instructions, one at a time. This sequence is the system’s physical control flow (or flow of control). Physical control flow <startup> inst1 inst2 inst3 instn <shutdown> Time

3 Altering the Control Flow
Up to Now: two mechanisms for changing control flow: Jumps and branches Call and return using the stack discipline. Both react to changes in program state. Insufficient for a useful system System should react to changes in system state Data arrives from a disk or a network adapter. Instruction divides by zero User hits ctl-alt-delete at the keyboard System timer expires Parent process that creates child processes must be notified when their children terminate System needs mechanisms for “exceptional control flow”

4 Exceptional Control Flow
Mechanisms for exceptional control flow exists at all levels of a computer system. At the hardware level Exceptions: caused by an internal event created by the currently running process Interrupts Caused by an external event asynchronously Implemented by combination of hardware and OS software At the operating system level Process context switch System calls Provide applications with entry points into the operating system At the application level Signal A process can send a signal to another process that abruptly transfers control to a signal handler Nonlocal jumps (setjmp/longjmp) React to errors, which sidesteps the usual stack discipline and make nonlocal jumps to arbitrary locations (implemented by C language runtime library)

5 Exceptions An exception is a transfer of control to the OS in response to some event (i.e., change in processor state) Implemented partly by the hardware and partly by the operating system Event might be related to the execution of current instruction (exception) Event might be unrelated to the execution of current instruction (interrupt) On event, the processor makes an indirect procedure call (to the exception handler) through a jump table called exception table User Process OS current exception event next exception processing by exception handler exception return (optional)

6 (Synchronous) Exceptions
Caused by events that occur as a result of executing an instruction: Traps Intentional exceptions Examples: system calls, breakpoints, special instructions Executing the syscall instruction causes a trap to an exception handler that decodes the argument and calls the appropriate kernel routine (run in kernel mode) Returns control to “next” instruction Faults Unintentional but possibly recoverable Examples: page faults (recoverable), protection faults (unrecoverable). Either re-executes faulting (“current”) instruction or terminate the process Aborts Unintentional and unrecoverable fatal errors Examples: parity error, machine check. Aborts the current process, and probably the entire system

7 Interrupt (Asynchronous Exception)
Caused by events external to the processor Indicated by setting the processor’s interrupt pin Handler returns to “next” instruction. Examples: I/O interrupts Hitting ctl-c at the keyboard, arrival of a packet from a network, arrival of a data sector from a disk Hard reset interrupt: hitting the reset button Soft reset interrupt: hitting ctl-alt-delete on a PC (2) Control passes to handler after current instruction finishes (1) Interrupt pin goes high during execution of current instruction Icurr Inext (3) Interrupt handler runs (4) Handler returns to next instruction

8 (External) Interrupt Interrupt Classification Maskable interrupt
Can be disabled/enabled by an instruction Generated by asserting INTR pin External interrupt controllers Intel 8259 PIC (programmable interrupt controller) delivers the interrupt vectors on the system bus during interrupt acknowledge cycle Non-maskable interrupt (NMI) Cannot be disabled by program Received on the processor’s NMI# input pin

9 Exception Handling Procedure
Flush all the instructions fetched subsequent to the instruction causing the condition from the pipeline Drain the pipeline Complete all outstanding write operations prior to the faulting instruction Save the PC of the next instruction to execute Also need to save the necessary registers and stack pointers to allow it to restore itself to its state Vector the interrupt Fetch instructions from the ISR and service the interrupt Return from the interrupt

10 Exception vs. Procedure Call
Differences As with procedure call, CPU pushes return address on the stack before jumping to the handler. But, the return address is either the current instruction or the next instruction depending on the event. CPU pushes some additional processor state onto the stack such as EEFLAGS register that contains condition codes All of these states are pushed onto the kernel’s stack rather than on the user’s stack Exception handlers run in kernel mode After the hander processes the event, the handler (optionally) returns to the interrupted program by executing a special “return from interrupt” instruction, which pops states back into the registers (restoring user states)

11 Interrupt (Exception) Vectors
An exception table is a jump table where entry k contains the address of the handler for exception k Start address of the exception table is contained in a special CPU register called the exception table base register. Each type of event has a unique exception number k. Using the exception number as an index, you can fetch the address of the corresponding handler. The index of the jump table (or the corresponding entry in the jump table) is called interrupt vector Handler k is called each time exception k occurs. Exception numbers code for exception handler 0 interrupt vector code for exception handler 1 1 code for exception handler 2 2 ... ... n-1 code for exception handler n-1

12 Trap Example Opening a File User calls open(filename, options)
Function open executes system call instruction int OS must find or create file, get it ready for reading or writing Returns integer file descriptor 0804d070 <__libc_open>: . . . 804d082: cd int $0x80 804d084: 5b pop %ebx User Process OS int exception pop Open file return

13 Fault Example #1 Memory Reference User writes to memory location
int a[1000]; main () { a[500] = 13; } Memory Reference User writes to memory location That portion (page) of user’s memory is currently on disk Page handler must load page into physical memory Returns to faulting instruction Successful on second try 80483b7: c d d movl $0xd,0x8049d10 User Process OS page fault Create page and load into memory return event movl

14 Fault Example #2 Memory Reference User writes to memory location
int a[1000]; main () { a[5000] = 13; } Memory Reference User writes to memory location Address is not valid Page handler detects invalid address Sends SIGSEG signal to user process User process exits with “segmentation fault” 80483b7: c e d movl $0xd,0x804e360 User Process OS page fault event movl Detect invalid address Signal process

15 Exceptions in Intel Processors
Pentium system can have up to 256 different exception types The first 32 exceptions (exception 0-31) are defined by the Pentium architecture and identical to any Pentium-class system. Exceptions correspond to traps and interrupts defined by OS Examples Exception 0 Divide by 0 Fault Unix does not attempt to recover from divide errors, opting instead to abort program. Unix shell report divide errors as “floating point exceptions”. Exception 13 General protection fault Fault Program references an undefined area of virtual memory, or write into read-only segment. Unix shell report as “segmentation fault”. Exception 14 Page fault Fault Exception 18 Machine check Abort OS-defined exceptions Interrupt or trap 128 (0x80) System call Trap System calls are provided via a trapping instruction called INT n, where n can be the index of any of the 256 entries in the exception table (software interrupt). OS-defined exceptions Interrupt or trap

16 Processes Def: A process is an instance of a program in execution.
One of the most profound ideas in computer science. Not the same as “program” or “processor” Process provides each program with two key abstractions: Logical control flow Each program seems to have exclusive use of the CPU. Private address space Each program seems to have exclusive use of main memory. How are these Illusions maintained? Multitasking: process executions are interleaved In reality, many other programs are running on the system. Processes take turns in using the processor Each time period that a process executes a portion of its flow is called a time slice Virtual memory: memory system provides a private space for each process The private space is also called the virtual address space, which is a linear array of bytes, addressed by n bit virtual address (0, 1, 2, 3, … 2n-1)

17 Private Address Spaces
Each process has its own private address space. 0xffffffff kernel virtual memory (code, data, heap, stack) memory invisible to user code 0xc user stack (created at runtime) %esp (stack pointer) memory mapped region for shared libraries 0x brk run-time heap (managed by malloc) read/write segment (.data, .bss) loaded from the executable file read-only segment (.init, .text, .rodata) 0x unused

18 Logical Control Flows Each process has its own logical control flow
Process A Process B Process C Time

19 Concurrent Processes Concurrent processes Examples:
Two processes run concurrently (are concurrent) if their flows overlap in time. Otherwise, they are sequential. Examples: Concurrent: A & B, A & C Sequential: B & C Control flows for concurrent processes are physically disjoint in time. However, we can think of concurrent processes as logically running in parallel with each other. Time Process A Process B Process C Time Process A Process B Process C

20 Context Switching Processes are managed by a shared chunk of OS code called the kernel Important: the kernel is not a separate process, but rather runs as part of some user process Processors typically provide this capability with a mode bit in some control register User mode and kernel mode If the mode bit is set, the process is running in kernel mode (supervisor mode), and can execute any instruction and can access any memory location If the mode bit is not set, the process is running in user mode and is not allowed to execute privileged instructions A process running application code is initially in user mode The only way to change from user mode to kernel mode is via an exception and exception handler runs in kernel mode

21 Context Switching Context Context switching
The kernel maintains a context for each process The context is the state of a process that the kernel needs to restart a preempted process Consist of general purpose registers, FP registers, PC, user’s stack, status registers, kernel’s stack, and various kernel data structures such as page table and file table Context switching The OS kernel implements multitasking using an exceptional control flow At certain points during the execution of a process, the kernel decide to preempt the current process and restart a previously preempted process This is called scheduling and handled by code in the kernel called scheduler The kernel first saves the context of the current process The kernel restores the context of some previously preempted process Then, the kernel passes control to this newly restored process

22 Context Switching Process A code Process B code Time user code
read context switch kernel code Time user code disk interrupt context switch kernel code return from read user code

23 fork: Creating new processes
Process control Unix provides a number of system calls for manipulating processes from C program Obtain Process ID, Create/Terminate Process, etc. int fork(void) Creates a new process (child process) that is identical to the calling process (parent process) Returns 0 to the child process Returns child’s pid to the parent process if (fork() == 0) { printf("hello from child\n"); } else { printf("hello from parent\n"); } Fork is interesting (and often confusing) because it is called once but returns twice

24 Fork Example #1 Parent and child both run the same code
Distinguish parent from child by return value from fork Duplicate but separate address space Start with same state, but each has private copy Relative ordering of their print statements undefined Shared files Both parent and child print their output on the same screen void fork1() { int x = 1; pid_t pid = fork(); if (pid == 0) { printf("Child has x = %d\n", ++x); } else { printf("Parent has x = %d\n", --x); } printf("Bye from process %d with x = %d\n", getpid(), x);

25 Fork Example #2 Both parent and child can continue forking
Process graph Each horizontal arrow corresponds to a process Each vertical arrow corresponds to the execution of a fork function void fork2() { printf("L0\n"); fork(); printf("L1\n"); printf("Bye\n"); } Bye L1 L0

26 Fork Example #3 Key Points Both parent and child can continue forking
void fork3() { printf("L0\n"); fork(); printf("L1\n"); printf("L2\n"); printf("Bye\n"); } L1 L2 Bye L0

27 Midterm Exam 3 void end(void) { printf(“2”); } int main()
int main() if (fork() == 0) { atexit (end); if (fork() == 0) printf(“hello”); if (fork() != 0) printf(“0”); else printf(“1”); printf(“bye”); exit(0); 1 bye 1 bye 0 bye 2 1 bye hello 0 bye

28 Fork Example #4 Key Points Both parent and child can continue forking
void fork4() { printf("L0\n"); if (fork() != 0) { printf("L1\n"); printf("L2\n"); fork(); } printf("Bye\n"); L1 Bye L2 Bye Bye L0

29 Fork Example #5 Key Points Both parent and child can continue forking
void fork5() { printf("L0\n"); if (fork() == 0) { printf("L1\n"); printf("L2\n"); fork(); } printf("Bye\n"); Bye Bye L2 Bye L1 L0

30 exit: Destroying Process
void exit(int status) Terminate a process with an exit status Normally with status 0 atexit() registers functions to be executed upon exit A process can be terminated for one of three reasons Call the exit function Return from the main function Receive a signal whose default action is to terminate the process void cleanup(void) { printf("cleaning up\n"); } void fork6() { atexit(cleanup); fork(); exit(0);

31 Reaping Child Process Zombie Reaping What if Parent Doesn’t Reap?
When a process terminates, the kernel does not remove it from the system immediately 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 Living corpse, half alive and half dead Zombie still consumes system resources such as various tables maintained by OS Reaping Performed by the parent on a terminated child Parent is given an exit status information Kernel discards process What if Parent Doesn’t Reap? If any parent terminates without reaping a child, then child will be reaped by init process The init process has a PID of 1 and is created by the kernel during system initialization. Long-running programs such as shells or servers should always reap their zombie children.

32 Zombie Example ps shows child process as “defunct”
void fork7() { if (fork() == 0) { /* Child */ printf("Terminating Child, PID = %d\n", getpid()); exit(0); } else { printf("Running Parent, PID = %d\n", while (1) ; /* Infinite loop */ } linux> ./forks 7 & [1] 6639 Running Parent, PID = 6639 Terminating Child, PID = 6640 linux> ps PID TTY TIME CMD 6585 ttyp :00:00 tcsh 6639 ttyp :00:03 forks 6640 ttyp :00:00 forks <defunct> 6641 ttyp :00:00 ps linux> kill 6639 [1] Terminated 6642 ttyp :00:00 ps ps shows child process as “defunct” Killing parent allows child to be reaped

33 Nonterminating Child Example
void fork8() { if (fork() == 0) { /* Child */ printf("Running Child, PID = %d\n", getpid()); while (1) ; /* Infinite loop */ } else { printf("Terminating Parent, PID = %d\n", exit(0); } linux> ./forks 8 Terminating Parent, PID = 6675 Running Child, PID = 6676 linux> ps PID TTY TIME CMD 6585 ttyp :00:00 tcsh 6676 ttyp :00:06 forks 6677 ttyp :00:00 ps linux> kill 6676 6678 ttyp :00:00 ps Child process still active even though parent has terminated Must kill explicitly, or else will keep running indefinitely

34 wait: Synchronizing with Children
int wait(int *child_status) Suspends the current process until one of its children terminates The terminated child is removed from the system. Return value is the pid of the child process that terminated if child_status != NULL, then it will be set to a status indicating why the child process terminated void fork9() { int child_status; if (fork() == 0) { printf("HC: hello from child\n"); } else { printf("HP: hello from parent\n"); wait(&child_status); printf("CT: child has terminated\n"); printf("Bye\n"); exit(); HP HC Bye CT Bye

35 Wait Example If multiple children completed, will take in arbitrary order Can use macros WIFEXITED and WEXITSTATUS to get information about exit status WIFEEXITED returns true if the child terminated normally void fork10() { pid_t pid[N]; int i; int child_status; for (i = 0; i < N; i++) if ((pid[i] = fork()) == 0) exit(100+i); /* Child */ for (i = 0; i < N; i++) { pid_t wpid = wait(&child_status); if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminate abnormally\n", wpid); }

36 Waitpid waitpid(pid, &status, options) Can wait for specific process
Various options void fork11() { pid_t pid[N]; int i; int child_status; for (i = 0; i < N; i++) if ((pid[i] = fork()) == 0) exit(100+i); /* Child */ for (i = 0; i < N; i++) { pid_t wpid = waitpid(pid[i], &child_status, 0); if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminated abnormally\n", wpid); }

37 Wait/Waitpid Example Outputs
Using wait (fork10) Child 3565 terminated with exit status 103 Child 3564 terminated with exit status 102 Child 3563 terminated with exit status 101 Child 3562 terminated with exit status 100 Child 3566 terminated with exit status 104 Using waitpid (fork11) Child 3568 terminated with exit status 100 Child 3569 terminated with exit status 101 Child 3570 terminated with exit status 102 Child 3571 terminated with exit status 103 Child 3572 terminated with exit status 104

38 exec: Running new programs
int execl(char *path, char *arg0, char *arg1, …, 0) Load and run executable at path with args arg0, arg1, … path is the complete path of an executable arg0 becomes the name of the process typically arg0 is either identical to path, or else it contains only the executable filename from path “real” arguments to the executable start with arg1, etc. list of args is terminated by a (char *)0 argument returns -1 if error, otherwise doesn’t return! Calls once but never returns main() { if (fork() == 0) { execl("/usr/bin/cp", "cp", "foo", "bar", 0); } wait(NULL); printf("copy completed\n"); exit();

39 exec: Running new programs
(Dynamic linker variables) Null-terminated environment variable strings command-line arg strings (Unused) envp[n] == NULL envp[n-1] ... envp[0] argv[argc] = NULL argv[argc-1] argv[0] argv argc Stack frame for main environ Bottom of stack Top of stack envp int execve(char *filename, char *argv[], char *envp[]); Load and run the executable with argument list argv and the environment variable list envp After execve loads the filename, it calls the startup code, which set up the stack and passes control to the main routine int main(int argc, char *argv[], char *envp[]); When main begins executing, the user stack has the organization shown on the right side

40 Environment Variables
A set of dynamic named values that can affect the way running processes will behave on a computer. Create the operating environment in which a process runs. All Unix operating system flavors, MS-DOS, and Microsoft Windows have environment variables; however, they do not all use the same variable names. Examples of environment variables PATH - lists directories the shell searches for the commands HOME - indicate where a user's home directory is located in the file system TERM - specifies the type of computer terminal (e.g., vt100). PS1 - specifies how the prompt is displayed MAIL - used to indicate where a user's mail is to be found. TEMP - location where processes can store temporary files

41 The World of Multitasking
System Runs Many Processes Concurrently Process: executing program State consists of memory image + register values + program counter Continually switches from one process to another Suspend process when it needs I/O resource or timer event occurs Resume process when it is given scheduling priority Appears to user(s) as if all processes executing simultaneously Even though most systems can only execute one process at a time Except possibly with lower performance than if running alone

42 Programmer’s Model of Multitasking
Basic Functions fork() spawns new process Called once, returns twice exit() terminates own process Called once, never returns Puts it into “zombie” status wait() and waitpid() wait for and reap terminated children execl() and execve() run a new program in an existing process Called once, (normally) never returns Programming Challenge Understanding the nonstandard semantics of the functions Avoiding improper use of system resources E.g. “Fork bombs” can disable a system.

43 Unix Process Hierarchy
[0] init [1] Daemon e.g. httpd Login shell Child Child Child Grandchild Grandchild

44 Process 0 forks child process 1
Unix Startup: Step 1 1. Pushing reset button loads the PC with the address of a small bootstrap program. 2. Bootstrap program loads the boot block (disk block 0). 3. Boot block program loads kernel binary (e.g., /boot/vmlinux) 4. Boot block program passes control to kernel. 5. Kernel handcrafts the data structures for process 0. [0] Process 0: handcrafted kernel process Process 0 forks child process 1 init [1] Child process 1 execs /sbin/init

45 Unix Startup: Step 2 [0] /etc/inittab init [1]
init forks and execs daemons per /etc/inittab, and forks and execs a getty program for the console Daemons e.g. ftpd, httpd getty

46 Unix Startup: Step 3 [0] init [1]
The getty process execs a login program login

47 Unix Startup: Step 4 [0] init [1] login reads login and passwd.
if OK, it execs a shell. if not OK, it execs another getty tcsh

48 Shell Programs A shell is an interactive application-level program that runs other programs on behalf of the user. sh – Original Unix Bourne Shell csh – BSD Unix C Shell, tcsh – Enhanced C Shell bash –Bourne-Again Shell int main() { char cmdline[MAXLINE]; while (1) { /* read */ printf("> "); Fgets(cmdline, MAXLINE, stdin); if (feof(stdin)) exit(0); /* evaluate */ eval(cmdline); } Execution is a sequence of read/evaluate steps

49 Simple Shell eval Function
void eval(char *cmdline) { char *argv[MAXARGS]; /* argv for execve() */ int bg; /* should the job run in bg or fg? */ pid_t pid; /* process id */ bg = parseline(cmdline, argv); /* build the argv vector */ if (!builtin_command(argv)) { if ((pid = Fork()) == 0) { /* child runs user job */ if (execve(argv[0], argv, environ) < 0) { printf("%s: Command not found.\n", argv[0]); exit(0); } if (!bg) { /* parent waits for fg job to terminate */ int status; if (waitpid(pid, &status, 0) < 0) unix_error("waitfg: waitpid error"); else /* otherwise, don’t wait for bg job */ printf("%d %s", pid, cmdline);

50 Problem with Simple Shell Example
Shell correctly waits for and reaps foreground jobs. But what about background jobs? Will become zombies when they terminate. Will never be reaped because shell (typically) will not terminate. Creates a memory leak that will eventually crash the kernel when it runs out of memory. Solution: Reaping background jobs requires a mechanism called a signal.

51 Signals A signal is a small message that notifies a process that an event of some type has occurred in the system. Signals provide a mechanism for exposing the occurrence of such exceptions to user processes. Kernel abstraction for exceptions and interrupts. Sent from the kernel (sometimes at the request of another process) to a process. Different signals are identified by small integer ID’s Each signal type corresponds to some kind of system event The only information in a signal is its ID and the fact that it arrived. ID Name Default Action Corresponding Event 2 SIGINT Terminate Interrupt from keyboard (ctl-c) 9 SIGKILL Kill program (cannot override or ignore) 11 SIGSEGV Terminate & Dump Segmentation violation 14 SIGALRM Timer signal 17 SIGCHLD Ignore Child stopped or terminated

52 Signal Concepts Sending a signal Receiving a signal
Kernel sends (delivers) a signal to a destination process by updating some state in the context of the destination process. Kernel sends a signal for one of the following reasons: Kernel has detected a system event such as divide-by-zero (SIGFPE) or the termination of a child process (SIGCHLD) Another process has invoked the kill system call to explicitly request the kernel to send a signal to the destination process. 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. Three possible ways to react: Ignore the signal (do nothing) Terminate the process. Catch the signal by executing a user-level function called a signal handler. Akin to a hardware exception handler being called in response to an asynchronous interrupt.

53 Signal Concepts (cont)
A signal is pending if it has been sent but not yet received. There can be at most one pending signal of any particular type. Important: Signals are not queued If a process has a pending signal of type k, then subsequent signals of type k that are sent to that process are discarded. A process can block the receipt of certain signals. Blocked signals can be delivered, but will not be received until the signal is unblocked. Kernel maintains pending and blocked bit vectors in the context of each process. pending – represents the set of pending signals Kernel sets bit k in pending whenever a signal of type k is delivered. Kernel clears bit k in pending whenever a signal of type k is received blocked – represents the set of blocked signals Can be set and cleared by the application using the sigprocmask function.

54 Process Groups Every process belongs to exactly one process group
Shell pid=10 pgid=10 Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Background process group 40 Child Child getpgrp() – Return process group of current process setpgid() – Change process group of a process pid=21 pgid=20 pid=22 pgid=20 Foreground process group 20

55 Sending Signals with kill Program
kill program sends arbitrary signal to a process or process group Examples kill – Send SIGKILL to process 24818 kill –9 –24817 Send SIGKILL to every process in process group linux> ./forks 16 linux> Child1: pid=24818 pgrp=24817 Child2: pid=24819 pgrp=24817 linux> ps PID TTY TIME CMD 24788 pts/ :00:00 tcsh 24818 pts/ :00:02 forks 24819 pts/ :00:02 forks 24820 pts/ :00:00 ps linux> kill 24823 pts/ :00:00 ps linux>

56 Sending Signals from the Keyboard
Typing ctrl-c (ctrl-z) sends a SIGINT (SIGTSTP) to every process in the foreground process group. SIGINT – termination signal; default action is to terminate each process SIGTSTP – stop signal; default action is to stop (suspend) each process Job: abstraction to represent the processes that are created by a command line. There is at most one foreground job and more background jobs Shell pid=10 pgid=10 Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Background process group 40 Child Child pid=21 pgid=20 pid=22 pgid=20 Foreground process group 20

57 Example of ctrl-c and ctrl-z
linux> ./forks 17 Child: pid=24868 pgrp=24867 Parent: pid=24867 pgrp=24867 <typed ctrl-z> Suspended linux> ps a PID TTY STAT TIME COMMAND 24788 pts/2 S :00 -usr/local/bin/tcsh -i 24867 pts/2 T :01 ./forks 17 24868 pts/2 T :01 ./forks 17 24869 pts/2 R :00 ps a bass> fg ./forks 17 <typed ctrl-c> 24870 pts/2 R :00 ps a

58 Sending Signals with kill Function
void fork12() { pid_t pid[N]; int i, child_status; for (i = 0; i < N; i++) if ((pid[i] = fork()) == 0) while(1); /* Child infinite loop */ /* Parent terminates the child processes */ for (i = 0; i < N; i++) { printf("Killing process %d\n", pid[i]); kill(pid[i], SIGINT); } /* Parent reaps terminated children */ pid_t wpid = wait(&child_status); if (WIFEXITED(child_status)) printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminated abnormally\n", wpid);

59 Receiving Signals Suppose kernel is returning from exception handler and is ready to pass control to process p. Kernel computes pnb = pending & ~blocked The set of pending nonblocked signals for process p If (pnb == 0) Pass control to next instruction in the logical flow for p. Else Choose least nonzero bit k in pnb and force process p to receive signal k. The receipt of the signal triggers some action by p Repeat for all nonzero k in pnb. Pass control to next instruction in logical flow for p.

60 Default Actions Each signal type has a predefined default action, which is one of: The process terminates The process terminates and dumps core. The process stops until restarted by a SIGCONT signal. The process ignores the signal.

61 Installing Signal Handlers
The signal function modifies the default action associated with the receipt of signal signum: handler_t *signal(int signum, handler_t *handler) Different values for handler: SIG_IGN: ignore signals of type signum SIG_DFL: revert to the default action on receipt of signals of type signum. Otherwise, handler is the address of a user-defined function called signal handler Called when process receives signal of type signum Changing the default action by passing the address of a handler to the signal function is known as “installing” the handler. The invocation of the handler is called “catching” the signal The execution of the handler is referred as “handling” the signal. When the handler executes its return statement, control passes back to instruction in the control flow of the process that was interrupted by receipt of the signal.

62 Signal Handling Example
#include "csapp.h" void handler(int sig) { static int beeps = 0; printf("BEEP\n"); if (++beeps < 5) Alarm(1); /* next SIGALRM will be delivered in 1s */ else { printf("BOOM!\n"); exit(0); } int main() { Signal(SIGALRM, handler); /* install SIGALRM handler */ Alarm(1); /* next SIGALRM will be delivered in 1s */ while (1) { ; /* signal handler returns control here each time */ } linux> ./alarm BEEP BOOM! linux>

63 Signal Handler Funkiness
int ccount = 0; void child_handler(int sig) { int child_status; pid_t pid = wait(&child_status); ccount--; printf("Received signal %d from process %d\n", sig, pid); } void fork14() pid_t pid[N]; int i, child_status; ccount = N; signal(SIGCHLD, child_handler); for (i = 0; i < N; i++) if ((pid[i] = fork()) == 0) { /* Child: Exit */ exit(0); while (ccount > 0) pause();/* Suspend until signal occurs */ Pending signals are blocked While the handler is processing the first signal, the second signal is delivered but cannot be received since SIGCHLD signals are blocked by the handler. Pending signals are not queued For each signal type, there can be at most one pending signal of a particular type. Meanwhile, the third SIGCHLD signal arrives but since there is already a pending SIGCHLD signal and the third signal is discarded!

64 Living With Nonqueuing Signals
To fix the problem, need to handle as many zombie children as possible each time the handler is invoked. Typically implemented with a while loop with wait void child_handler2(int sig) { int child_status; pid_t pid; while ((pid = wait(&child_status)) > 0) { ccount--; printf("Received signal %d from process %d\n", sig, pid); } void fork15() . . . signal(SIGCHLD, child_handler2);

65 Nonlocal Jumps: setjmp/longjmp
Powerful (but dangerous) user-level mechanism for transferring control to an arbitrary location. Controlled to way to break the procedure call/return discipline Useful for error recovery and signal handling Immediate return from a deeply nested function call (as a result of detecting some error condition) Branch out of a signal handler to a specific code location, rather than returning to the instruction interrupted int setjmp(jmp_buf j) Must be called before longjmp Save the current stack context in the buffer j, for later use by longjump Identify a return site for a subsequent longjmp. Remember where you are by storing the current register context, stack pointer, and PC value in the buffer j Return 0 initially Called once, returns one or more times void longjmp(jmp_buf j, int i) Restore the stack context from the j buffer and then return to the most recent setjmp call Jump to the location indicated by the PC stored in jump buf j. Provide a non-zero return value I to the setjmp Called once, but never returns

66 setjmp/longjmp Example
#include <setjmp.h> jmp_buf buf; main() { if (setjmp(buf) != 0) { printf("back in main due to an error\n"); else printf("first time through\n"); p1(); /* p1 calls p2, which calls p3 */ } ... p3() { <error checking code> if (error) longjmp(buf, 1)

67 Putting It All Together: A Program That Restarts Itself When ctrl-c’d
#include <stdio.h> #include <signal.h> #include <setjmp.h> sigjmp_buf buf; void handler(int sig) { siglongjmp(buf, 1); } main() { signal(SIGINT, handler); if (!sigsetjmp(buf, 1)) printf("starting\n"); else printf("restarting\n"); while(1) { sleep(1); printf("processing...\n"); } bass> a.out starting processing... restarting Ctrl-c Ctrl-c Ctrl-c


Download ppt "Computer System Chapter 8. Exceptional Control Flow"

Similar presentations


Ads by Google