250 likes | 346 Views
Outline Exceptions Process Signals Non-local jumps Reminders Lab4: Due Next Thursday. TA: Kun Gao Shamelessly Modified from Minglong Shao’s Recitation, Fall 2004. Section A (March 14). Exceptional control flow (ECF). Abrupt changes in the control flow
E N D
Outline Exceptions Process Signals Non-local jumps Reminders Lab4: Due Next Thursday TA: Kun Gao Shamelessly Modified from Minglong Shao’s Recitation, Fall 2004 Section A (March 14)
Exceptional control flow (ECF) • Abrupt changes in the control flow • React to changes in system state that are not captured by internal program variables and are not necessarily related to the execution of the program • Happens at all levels of a computer system • Exceptions • Concurrent processes • Signals • Non-local jumps
Exceptions • Interrupt (asynchronous exceptions) • I/O interrupt, hardware reset, software reset, etc. • Traps • System calls, breakpoint traps, etc. • Faults • Page fault, protection fault, etc. • Aborts • Parity error, machine check, etc.
Process concept • An instance of running program • Multiple processes run “concurrently” by time slicing • Context switching • Control flow passes from one process to another • Preemptive scheduler of OS • Process vs Threads (a favorite interview question) • Threads are logical flows that run in the context of a single process
Process IDs & process groups • A process has its own, unique process ID • pid_t getpid(); • A process belongs to exactly one process group • pid_t getpgrp(); • A new process belongs to which process group? • Its parent’s process group • A process can make a process group for itself and its children • setpgid(0, 0);
Create a new process • int fork(void) • Create a new process that is identical to the parent process • Return 0 to child process • Return child’s pid to the parent process • Call once, return twice • Test your understanding… • Problem 1
Problem 1 #include <unistd.h> #include <stdio.h> int cnt = 0; int main(void) { if (fork() == 0){ cnt ++; fork(); cnt++; } cnt ++; printf("%d", cnt); return 0; } Possible output: 133 313 331
Reaping child process • Child process becomes zombie when terminates • Still consume system resources • Parent performs reaping on terminated child pid_t wait(int *status) pid_t waitpid(pid_t pid, int *status, int options) • Straightforward for reaping a single child • Tricky for Shell implementation! • Multiple child processes • Both foreground and background
Signals • Section 8.5 in text • Read at least twice … really! • A signal tells our program that some event has occurred
Important signals (Fig 8.23) • SIGINT • Interrupt signal from terminal (ctrl-c) • SIGTSTP • Stop signal from terminal (ctrl-z) • SIGCHLD • A child process has stopped or terminated
How to Send Signals • Process • int kill(pid_t pid, int sig) • Groups • int kill(pid_t gid, int sig), where gid is negative • Process can also send a signal to itself • int alarm(unsigned int secs) to send a SIGALRM signal • Can we use signals to count events? • No • Why? Signals not queued!!
Process 1 blocked pending kill(pid, SIGINT) other events Signals: sending Process 2 1 OS procedure • divide by zero: SIGFPE • ctrl-c: SIGINT • child process exit: SIGCHLD OS Kernel
blocked pending Signals: receiving Process 2 Check when schedule the process to run 0 1 OS procedure OS Kernel
Receiving a signal • Default action • The process terminates [and dumps core] • The process stops until restarted by a SIGCONT signal (ctrl-z) • The process ignore the signal • Can modify (additional action) • “Handle the signal” -- install signal handler void sigint_handler(int sig); signal(SIGINT, sigint_handler); • An example: problem 3
Problem 3 void handler(int sig){ static int beeps = 0; printf("YO\n"); if (++beeps < 2) alarm(1); /* next SIGALRM will be delivered in 1s */ else{ printf("MA\n"); kill(getpid(), SIGKILL); } } int main(){ signal(SIGALRM, handler); alarm(1); /* next SIGALRM will be delivered in 1s */ while (1) ; printf(" is Great!\n"); return 0; } 1. Output: YO YO MA 2. The program will terminate
Signals not queued int counter = 0; void handler(int sig) { counter++; sleep(1); return; } int main() { int i; signal(SIGUSER2, handler); if (fork() == 0){ for (i = 0; i < 5; i++){ kill(getppid(), SIGUSR2); printf(“sent SIGUSR2 to parent\n”); } exit(0); } wait(NULL); printf(“counter = %d\n”, counter); exit(0); } Output: sent SIGUSR2 to parent sent SIGUSR2 to parent sent SIGUSR2 to parent sent SIGUSR2 to parent sent SIGUSR2 to parent counter = 1
Race hazard • A data structure is shared by two pieces of code that can run concurrently • Different behaviors of program depending upon how the schedule interleaves the execution of code.
An example of race hazard sigchld_handler() { pid = waitpid(…); deletejob(pid); } eval() { pid = fork(); if(pid == 0) { /* child */ execve(…); } /* parent */ /* signal handler may run BEFORE addjob()*/ addjob(…); }
An okay schedule Signal Handler Child time Shell fork() addjob() execve() exit() sigchld_handler() deletejobs()
A problematic schedule time Signal Handler Child Shell fork() execve() exit() sigchld_handler() deletejobs() addjob() Job added to job list after the signal handler tried to delete it!
Solution: blocking signals sigchld_handler() { pid = waitpid(…); deletejob(pid); } eval() { sigprocmask(SIG_BLOCK, …) pid = fork(); if(pid == 0) { /* child */ sigprocmask(SIG_UNBLOCK, …) /* child inherits parents block set */ execve(…); } /* parent */ /* signal handler might run BEFORE addjob() */ addjob(…); sigprocmask(SIG_UNBLOCK, …) } More details 8.5.6 (page 633)
Non-local jump int setjmp(jmp_buf env) • Must called before longjmp • Stores current register context, stack pointer, and PC in the jump buffer env • First called, return 0 if no error void longjmp(jmp_buf env, int i) • Restores register context from jump buffer env • Jumps back to where previous setjmp is called, behaves like setjmp just completes. But this time it returns i, not 0 Can only jump to an active context • A function that has been called but not yet completed
Non-local jump (cont) int sigsetjmp(jmp_buf env) • Also saves blocked signals void siglongjmp(jmp_buf env, int i) • Restores blocked signals besides others Let’s see an example: problem 4
Problem 4 jmp_buf stuff; int foo(){ char c = getc(stdin); if (c == 'x') longjmp(stuff, 42); else return 3; return -1; } int main() { int n; n = setjmp(stuff); while ((n+=foo())<0) sleep(1); printf("%d\n", n); } Answer: 1. 3 2. 45
Summary • Process • fork(), waitpid(), execve() • Reaping child processes • Signals • signal(), install handler, signals not queued • Non-local jumps • Check man page to understand the system calls better • man waitpid (fork, signal, …) • Read text book!