Computer System Chapter 8. Exceptional Control Flow

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

description

Computer System Chapter 8. Exceptional Control Flow. Lynn Choi Korea University. 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. - PowerPoint PPT Presentation

Transcript of Computer System Chapter 8. Exceptional Control Flow

  • Computer System

    Chapter 8. Exceptional Control FlowLynn ChoiKorea University

  • Control Flow

    inst1inst2inst3instn

    Computers do Only One ThingFrom startup to shutdown, a CPU simply reads and executes (interprets) a sequence of instructions, one at a time.This sequence is the systems physical control flow (or flow of control).

    Physical control flowTime

  • Altering the Control FlowUp to Now: two mechanisms for changing control flow:Jumps and branchesCall and return using the stack discipline.Both react to changes in program state.Insufficient for a useful systemSystem should react to changes in system stateData arrives from a disk or a network adapter.Instruction divides by zeroUser hits ctl-alt-delete at the keyboardSystem timer expiresParent process that creates child processes must be notified when their children terminateSystem needs mechanisms for exceptional control flow

  • Exceptional Control FlowMechanisms for exceptional control flow exists at all levels of a computer system.At the hardware levelExceptions: caused by an internal event created by the currently running processInterruptsCaused by an external event asynchronouslyImplemented by combination of hardware and OS softwareAt the operating system levelProcess context switchSystem callsProvide applications with entry points into the operating systemAt the application levelSignalA process can send a signal to another process that abruptly transfers control to a signal handlerNonlocal 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)

  • ExceptionsAn 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 systemEvent 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 tableUser ProcessOSexceptionexception processingby exception handler

    exception return (optional)event currentnext

  • (Synchronous) ExceptionsCaused by events that occur as a result of executing an instruction:TrapsIntentional exceptionsExamples: system calls, breakpoints, special instructionsExecuting 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 instructionFaultsUnintentional but possibly recoverable Examples: page faults (recoverable), protection faults (unrecoverable).Either re-executes faulting (current) instruction or terminate the processAbortsUnintentional and unrecoverable fatal errorsExamples: parity error, machine check.Aborts the current process, and probably the entire system

  • Interrupt (Asynchronous Exception)Caused by events external to the processorIndicated by setting the processors interrupt pinHandler returns to next instruction.Examples:I/O interruptsHitting ctl-c at the keyboard, arrival of a packet from a network, arrival of a data sector from a diskHard reset interrupt: hitting the reset buttonSoft reset interrupt: hitting ctl-alt-delete on a PC(2) Control passes to handler after currentinstruction finishes(3) Interrupt handler runs(4) Handlerreturns to next instructionIcurrInext(1) Interrupt pingoes high duringexecution of current instruction

  • (External) InterruptInterrupt ClassificationMaskable interruptCan be disabled/enabled by an instructionGenerated by asserting INTR pinExternal interrupt controllersIntel 8259 PIC (programmable interrupt controller) delivers the interrupt vectors on the system bus during interrupt acknowledge cycleNon-maskable interrupt (NMI)Cannot be disabled by programReceived on the processors NMI# input pin

  • Exception Handling ProcedureException handling procedure Flush all the instructions fetched subsequent to the instruction causing the condition from the pipelineDrain the pipeline Complete all outstanding write operations prior to the faulting instructionSave the PC of the next instruction to executeAlso 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 interruptReturn from the interrupt

  • Exception vs. Procedure CallDifferencesAs 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 codesAll of these states are pushed onto the kernels stack rather than on the users stackException handlers run in kernel modeAfter 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)

  • Interrupt (Exception) VectorsStart 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 vectorHandler k is called each time exception k occurs.

    interruptvector012...n-1code for exception handler 0code for exception handler 1code forexception handler 2code for exception handler n-1...Exception numbersAn exception table is a jump table where entry k contains the address of the handler for exception k

  • Trap ExampleUser ProcessOSexceptionOpen file

    returnintpopOpening a FileUser calls open(filename, options)

    Function open executes system call instruction intOS must find or create file, get it ready for reading or writingReturns integer file descriptor0804d070 : . . . 804d082:cd 80 int $0x80 804d084:5b pop %ebx . . .

  • Fault Example #1Memory ReferenceUser writes to memory locationThat portion (page) of users memory is currently on disk

    Page handler must load page into physical memoryReturns to faulting instructionSuccessful on second tryint a[1000];main (){ a[500] = 13;} 80483b7:c7 05 10 9d 04 08 0d movl $0xd,0x8049d10

  • Fault Example #2User ProcessOSpage faultDetect invalid addressevent movlMemory ReferenceUser writes to memory locationAddress is not valid

    Page handler detects invalid addressSends SIGSEG signal to user processUser process exits with segmentation faultint a[1000];main (){ a[5000] = 13;} 80483b7:c7 05 60 e3 04 08 0d movl $0xd,0x804e360Signal process

  • Exceptions in Intel ProcessorsPentium system can have up to 256 different exception typesThe first 32 exceptions (exception 0-31) are defined by the Pentium architecture and identical to any Pentium-class system.Exceptions 32-255 correspond to traps and interrupts defined by OSExamplesException 0Divide by 0FaultUnix does not attempt to recover from divide errors, opting instead to abort program. Unix shell report divide errors as floating point exceptions.Exception 13General protection faultFaultProgram references an undefined area of virtual memory, or write into read-only segment. Unix shell report as segmentation fault.Exception 14Page faultFaultException 18Machine checkAbort32-127OS-defined exceptionsInterrupt or trap128 (0x80)System callTrapSystem 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).129-255OS-defined exceptionsInterrupt or trap

  • ProcessesDef: 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 processorProcess provides each program with two key abstractions:Logical control flowEach program seems to have exclusive use of the CPU.Private address spaceEach program seems to have exclusive use of main memory.How are these Illusions maintained?Multitasking: process executions are interleavedIn reality, many other programs are running on the system.Processes take turns in using the processorEach time period that a process executes a portion of its flow is called a time sliceVirtual memory: memory system provides a private space for each processThe 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)

  • Private Address SpacesEach process has its own private address space.kernel virtual memory(code, data, heap, stack)memory mapped region forshared librariesrun-time heap(managed by malloc)user stack(created at runtime)unused0%esp (stack pointer)memoryinvisible touser codebrk0xc00000000x080480000x40000000read/write segment(.data, .bss)read-only segment(.init, .text, .rodata)loaded from the executable file0xffffffff

  • Logical Control FlowsTimeProcess AProcess BProcess CEach process has its own logical control flow

  • Concurrent ProcessesConcurrent processesTwo processes run concurrently (are concurrent) if their flows overlap in time.Otherwise, they are sequential. Examples:Concurrent: A & B, A & CSequential: 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.

  • Context SwitchingProcesses are managed by a shared chunk of OS code called the kernelImportant: the kernel is not a separate process, but rather runs as part of some user processProcessors typically provide this capability with a mode bit in some control registerUser mode and kernel modeIf the mode bit is set, the process is running in kernel mode (supervisor mode), and can execute any instruction and can access any memory locationIf the mode bit is not set, the process is running in user mode and is not allowed to execute privileged instructionsA process running application code is initially in user modeThe only way to change from user mode to kernel mode is via an exception and exception handler runs in kernel mode

  • Context SwitchingContextThe kernel maintains a context for each processThe context is the state of a process that the kernel needs to restart a preempted processConsist of general purpose registers, FP registers, PC, users stack, status registers, kernels stack, and various kernel data structures such as page table and file tableContext switchingThe OS kernel implements multitasking using an exceptional control flowAt certain points during the execution of a process, the kernel decide to preempt the current process and restart a previously preempted processThis is called scheduling and handled by code in the kernel called schedulerContext switchingThe kernel first saves the context of the current processThe kernel restores the context of some previously preempted processThen, the kernel passes control to this newly restored process

  • Context SwitchingProcess AcodeProcess Bcodeuser codekernel codeuser codekernel codeuser codeTimecontext switchcontext switchreaddisk interruptreturn from read

  • fork: Creating new processesProcess controlUnix provides a number of system calls for manipulating processes from C programObtain 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 processReturns childs 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 calledonce but returns twice

  • Fork Example #1void 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);}Parent and child both run the same codeDistinguish parent from child by return value from forkDuplicate but separate address spaceStart with same state, but each has private copyRelative ordering of their print statements undefinedShared filesBoth parent and child print their output on the same screen

  • Fork Example #2void fork2(){ printf("L0\n"); fork(); printf("L1\n"); fork(); printf("Bye\n");}Both parent and child can continue forkingProcess graphEach horizontal arrow corresponds to a processEach vertical arrow corresponds to the execution of a fork function

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

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

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

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

  • exit: Destroying Processvoid exit(int status)Terminate a process with an exit statusNormally with status 0atexit() registers functions to be executed upon exit

    A process can be terminated for one of three reasonsCall the exit functionReturn from the main functionReceive a signal whose default action is to terminate the process void cleanup(void) { printf("cleaning up\n");}

    void fork6() { atexit(cleanup); fork(); exit(0);}

  • Reaping Child ProcessZombieWhen a process terminates, the kernel does not remove it from the system immediatelyThe process is kept around in a terminated state until it is reaped by its parentA terminated process that has not yet been reaped is called a zombieLiving corpse, half alive and half deadZombie still consumes system resources such as various tables maintained by OSReapingPerformed by the parent on a terminated childParent is given an exit status informationKernel discards processWhat if Parent Doesnt Reap?If any parent terminates without reaping a child, then child will be reaped by init processThe 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.

  • linux> ./forks 7 &[1] 6639Running Parent, PID = 6639Terminating Child, PID = 6640linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6639 ttyp9 00:00:03 forks 6640 ttyp9 00:00:00 forks 6641 ttyp9 00:00:00 pslinux> kill 6639[1] Terminatedlinux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6642 ttyp9 00:00:00 psZombie Exampleps shows child process as defunctKilling parent allows child to be reapedvoid fork7(){ if (fork() == 0) {/* Child */printf("Terminating Child, PID = %d\n", getpid());exit(0); } else {printf("Running Parent, PID = %d\n", getpid());while (1) ; /* Infinite loop */ }}

  • linux> ./forks 8Terminating Parent, PID = 6675Running Child, PID = 6676linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6676 ttyp9 00:00:06 forks 6677 ttyp9 00:00:00 pslinux> kill 6676linux> ps PID TTY TIME CMD 6585 ttyp9 00:00:00 tcsh 6678 ttyp9 00:00:00 psNonterminating Child Example

    Child process still active even though parent has terminatedMust kill explicitly, or else will keep running indefinitelyvoid fork8(){ if (fork() == 0) {/* Child */printf("Running Child, PID = %d\n", getpid());while (1) ; /* Infinite loop */ } else {printf("Terminating Parent, PID = %d\n", getpid());exit(0); }}

  • wait: Synchronizing with Childrenint wait(int *child_status)Suspends the current process until one of its children terminatesThe terminated child is removed from the system.Return value is the pid of the child process that terminatedif child_status != NULL, then it will be set to a status indicating why the child process terminatedvoid 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();}

  • Wait ExampleIf multiple children completed, will take in arbitrary orderCan use macros WIFEXITED and WEXITSTATUS to get information about exit statusWIFEEXITED returns true if the child terminated normallyvoid 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); }}

  • Waitpidwaitpid(pid, &status, options)Can wait for specific processVarious optionsvoid 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); }

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

  • exec: Running new programsint 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 executablearg0 becomes the name of the processtypically arg0 is either identical to path, or else it contains only the executable filename from pathreal arguments to the executable start with arg1, etc.list of args is terminated by a (char *)0 argumentreturns -1 if error, otherwise doesnt return!Calls once but never returnsmain() { if (fork() == 0) { execl("/usr/bin/cp", "cp", "foo", "bar", 0); } wait(NULL); printf("copy completed\n"); exit();}

  • exec: Running new programsint execve(char *filename, char *argv[], char *envp[]);Load and run the executable with argument list argv and the environment variable list envpAfter execve loads the filename, it calls the startup code, which set up the stack and passes control to the main routineint main(int argc, char *argv[], char *envp[]);When main begins executing, the user stack has the organization shown on the right side

  • Environment VariablesEnvironment variablesA 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 variablesPATH - lists directories the shell searches for the commandsHOME - indicate where a user's home directory is located in the file systemTERM - specifies the type of computer terminal (e.g., vt100).PS1 - specifies how the prompt is displayedMAIL - used to indicate where a user's mail is to be found.TEMP - location where processes can store temporary files

  • The World of MultitaskingSystem Runs Many Processes ConcurrentlyProcess: executing programState consists of memory image + register values + program counterContinually switches from one process to anotherSuspend process when it needs I/O resource or timer event occursResume process when it is given scheduling priority Appears to user(s) as if all processes executing simultaneouslyEven though most systems can only execute one process at a timeExcept possibly with lower performance than if running alone

  • Programmers Model of MultitaskingBasic Functionsfork() spawns new processCalled once, returns twiceexit() terminates own processCalled once, never returnsPuts it into zombie statuswait() and waitpid() wait for and reap terminated childrenexecl() and execve() run a new program in an existing processCalled once, (normally) never returnsProgramming ChallengeUnderstanding the nonstandard semantics of the functionsAvoiding improper use of system resourcesE.g. Fork bombs can disable a system.

  • Unix Process HierarchyLogin shellChildChildChildGrandchildGrandchild[0]Daemone.g. httpdinit [1]

  • Unix Startup: Step 1init [1][0]Process 0: handcrafted kernel processChild process 1 execs /sbin/init1. 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.

    Process 0 forks child process 1

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

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

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

  • Shell ProgramsA shell is an interactive application-level program that runs other programs on behalf of the user.sh Original Unix Bourne Shellcsh 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

  • Simple Shell eval Functionvoid 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, dont wait for bg job */ printf("%d %s", pid, cmdline); }}

  • Problem with Simple Shell ExampleShell 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.

  • SignalsA 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 IDsEach signal type corresponds to some kind of system eventThe only information in a signal is its ID and the fact that it arrived.

    IDNameDefault ActionCorresponding Event2SIGINTTerminateInterrupt from keyboard (ctl-c)9SIGKILLTerminateKill program (cannot override or ignore)11SIGSEGVTerminate & DumpSegmentation violation14SIGALRMTerminateTimer signal17SIGCHLDIgnoreChild stopped or terminated

  • Signal Concepts Sending a signalKernel 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 signalA 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.

  • 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 queuedIf 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 signalsKernel 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 signalsCan be set and cleared by the application using the sigprocmask function.

  • Process GroupsEvery process belongs to exactly one process groupFore-groundjobBack-groundjob #1Back-groundjob #2ShellChildChildpid=10pgid=10Foregroundprocess group 20Backgroundprocess group 32Backgroundprocess group 40pid=20pgid=20pid=32pgid=32pid=40pgid=40pid=21pgid=20pid=22pgid=20getpgrp() Return process group of current processsetpgid() Change process group of a process

  • Sending Signals with kill Programkill program sends arbitrary signal to a process or process group

    Exampleskill 9 24818Send SIGKILL to process 24818kill 9 24817Send SIGKILL to every process in process group 24817. linux> ./forks 16 linux> Child1: pid=24818 pgrp=24817 Child2: pid=24819 pgrp=24817 linux> ps PID TTY TIME CMD 24788 pts/2 00:00:00 tcsh 24818 pts/2 00:00:02 forks 24819 pts/2 00:00:02 forks 24820 pts/2 00:00:00 ps linux> kill -9 -24817 linux> ps PID TTY TIME CMD 24788 pts/2 00:00:00 tcsh 24823 pts/2 00:00:00 ps linux>

  • Sending Signals from the KeyboardTyping 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 processJob: abstraction to represent the processes that are created by a command line.There is at most one foreground job and more background jobsFore-groundjobBack-groundjob #1Back-groundjob #2ShellChildChildpid=10pgid=10Foregroundprocess group 20Backgroundprocess group 32Backgroundprocess group 40pid=20pgid=20pid=32pgid=32pid=40pgid=40pid=21pgid=20pid=22pgid=20

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

  • Sending Signals with kill Functionvoid 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 */ 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 terminated abnormally\n", wpid); }}

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

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

  • Installing Signal HandlersThe 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 signumSIG_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 handlerCalled when process receives signal of type signumChanging 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 signalThe 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.

  • 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 */ } exit(0); }linux> ./alarm BEEPBEEPBEEPBEEPBEEPBOOM! linux>

  • Signal Handler FunkinessPending signals are blockedWhile 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 queuedFor 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!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 */}

  • Living With Nonqueuing SignalsTo 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 waitvoid 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); . . .}

  • Nonlocal Jumps: setjmp/longjmpPowerful (but dangerous) user-level mechanism for transferring control to an arbitrary location.Controlled to way to break the procedure call/return disciplineUseful for error recovery and signal handlingImmediate 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 interruptedint setjmp(jmp_buf j)Must be called before longjmpSave the current stack context in the buffer j, for later use by longjumpIdentify 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 jReturn 0 initiallyCalled once, returns one or more timesvoid longjmp(jmp_buf j, int i)Restore the stack context from the j buffer and then return to the most recent setjmp callJump to the location indicated by the PC stored in jump buf j. Provide a non-zero return value I to the setjmpCalled once, but never returns

  • setjmp/longjmp Example#include 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() { if (error) longjmp(buf, 1)}

  • Putting It All Together: A Program That Restarts Itself When ctrl-cd#include #include #include

    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.outstartingprocessing...processing...restartingprocessing...processing...processing...restartingprocessing...restartingprocessing...processing...Ctrl-cCtrl-cCtrl-c