Section A (March 14)
Outline Exceptions Process Signals Non-local jumps
Reminders Lab4:
Due Next Thursday
TA: Kun Gao
Shamelessly Modified from
Minglong Shao’sRecitation, Fall 2004
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:133313331
Reaping child process
Child process becomes zombie when terminates Still consume system resources Parent performs reaping on terminated childpid_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!!
Signals: sending
OS Kernel
blockedpending1
Process 1 Process 2
other events
OS procedure
kill(pid, SIGINT)
• divide by zero: SIGFPE
• ctrl-c: SIGINT
• child process exit: SIGCHLD
Signals: receiving
OS Kernel
blockedpending1
Process 2
OS procedure
0
Check when schedule the process to run
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 3void 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:YOYOMA2. The program will terminate
Signals not queuedint 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 parentsent SIGUSR2 to parentsent SIGUSR2 to parentsent SIGUSR2 to parentsent SIGUSR2 to parentcounter = 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
Shell Signal Handler Child
fork()
addjob()
execve()
exit()
sigchld_handler()
deletejobs()
time
A problematic schedule
Shell Signal Handler Child
fork()
execve()
exit()
sigchld_handler()
deletejobs()
time
addjob()
Job added to job list after the signal handler tried to delete it!
Solution: blocking signalssigchld_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 4jmp_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. 32. 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!