Control Flow
CPU
Sean Barker 1
Physical Control Flow
Physical control flow
instn
Sean Barker 2 Operating System
User-level Applications
Operating System
Hardware Resources
Sean Barker 3
Processes
Memory Memory Memory Stack Stack Stack Heap Heap Heap Data Data … Data Code Code Code
CPU CPU CPU Registers Registers Registers
Sean Barker 4 Control Flow Abstraction
Process A Process B Process C
Time
Sean Barker 5
Control Flow Time-Sharing
Process A Process B Process C
Time
Sean Barker 6 Context Switching
Process A Process B
user code
kernel code context switch
Time user code
kernel code context switch
user code 11/12/15
Sean Barker 7 Exceptions:'hardware/support/for/OS/ Interrupt'Vector stored/in/memory Exceptions special/register/holds/base/address transfer' control' to'OS'in'response' to'event What'code'should'the'OS'run'to'handle'the'event? code/for// Unique'ID'per'type'of'event exception/handler/ 0 Exception Ta bl e code/for/ ID'='index'into'exception'table' User-Process OS exception/handler/ 1 0 (a.k.a./interrupt/vector) 1 code/for exception 2 event' ... exception/handler/ 2 Handler'i is'called'each'time' exception'processing n&1 exception'i occurs by/exception'handler ... return'or'abort code/for/ exception/handler/ n<1
Exception/ numbers a/ jump/table/ for/exceptions… 9 10
Sean Barker 8
Open'a'file (trap/system/ call) Segmentation'Fault
User/process/calls:/open(filename, options) int a[1000]; open executes/system/call/instruction/int void bad () { Write/to/invalid/memory/location. a[5000] = 13; 0804d070 <__li b c _o p e n>: } . . . 804d082: cd 80 int $0x80 80483b7: c7 05 60 e3 04 08 0d movl $0xd,0x804e360 804d084: 5b pop %eb x . . . User-Process OS User-Process OS movl exception:'page'fault detect'invalid'address int exception pop signal'process open-file returns aborts/process/with/SIGSEGV/ signal
12 13
3 Example: Segmentation Fault
int a[1000]; main () { a[5000] = 13; }
80483b7: c7 05 60 e3 04 08 0d movl $0xd,0x804e360
User code Kernel code
Excep&on: page fault movl Detect invalid address Signal process
Sean Barker 9
Exception Table
Excep&on numbers
Code for excep&on handler 0
Excep&on Code for Table excep&on handler 1 0 1 Code for 2 ... excep&on handler 2 n-1 ...
Code for excep&on handler n-1
Sean Barker 10 Process Management
Memory Memory Memory Stack Stack Stack Heap Heap Heap Data Data … Data Code Code Code
CPU CPU CPU Registers Registers Registers
Sean Barker 11 11/12/15
Fork/Exec When.you.run.the.command.ls forkGexec ExecGing1a1new1program in.a.shell: forkGexec1model: Stack fork() clone.current.process Code/state.of.shell.process. execv() replace.process.code.and.context.(registers,.memory) with.a.fresh.program. 1 See.man131execv,.man.2.execv e Heap Replaced.by.code/state.of.ls. Data Copy.of.code/state. // Example arguments: path="/usr/bin/ls”, Code:./usr/bin/bash of.shell.process. // argv[0]="/usr/bin/ls”, argv[1]="-ahl", argv[2]=NULL fork(): void fork_exec(char* path, char* argv[]) { parent child child pid_t pid = fork(); Stack if (pid != 0) { Stack Stack printf("Parent: created a child %d\n”, pid); } else { exec(): printf("Child: exec-ing new program now\n"); 2 2 3 execv(path, argv); Heap Heap } Data Data Data printf("This line printed by parent only!\n"); Code:./usr/bin/bash Code:./usr/bin/bash Code:./usr/bin/ls } 6 Code/state.of.shell.process. 7
Sean Barker 12
execv: load/start1program exit:1end1a1process Stack-bottom NullYterminated int execv(char* filename, env var strings void exit(int status) End1process with.status:.0.=.normal,.nonzero.=.error. char* argv[]) NullYterminated argument.strings atexit() registers.functions.to.be.executed.upon.exit loads/starts1 program1 in1current1process: unused Executable.filename envp[n].==.NULL With.argument.list.argv envp[nY1] … overwrites1code,1data,1 and1stack envp[0] Keeps.pid,.open.files,.a.few.other.items. argv[argc]. ==. NULL does-not-return argv[argcY1] … unless.error argv[0] Linker.vars envp argv Also.sets.up environment...See.also:.execve. argc Stack. frame.for. main Stack-top 8 9
2 Zombies!
Sean Barker 13 11/12/15
Reaping: waitpid
Zombies! wait for.child.processes.to.terminate
Terminated1 process1still1consumes1system1resources pid_t waitpid(pid_t pid, int* stat, int ops) Various.tables.maintained.by.OS Suspend.current.process.(i.e..parent).until.child.with.pid ends. A.living.corpse,.half.alive.and.half.dead On.success: Reaping1with wait/waitpid waitReturn. setpid when.child.terminates. Parent.waits to.reap.child.once.child.terminates Reap.child. Parent.receives.child.exit.status. Kernel.discards.process. If.stat != NULL,. waitpid saves.termination. reason. where. it. points. What1if1parent1doesn’t1reap? If.any.parent.terminates.without.reaping.a.child,.then.child.will.be.reaped. See. also:.man&3&waitpid by.init process.(pid.==.1) But.in.longYrunning.processes.we.need.explicit reaping e.g.,.shells.and.servers
Sean Barker 14
10 11
waitpid example HCBye ErrorGchecking
CTBye Check1return1results1of1system1calls1for1errors!1(No.exceptions.) void fork_wait() { Read.documentation. for.return.values. int child_status; pid_t child_pid == fork(); Use.perror to.report.error,. then.exit. if (child_pid == 0) { printf("HC: hello from child\n"); void perror(char* message) } else { Print."message:. reason.that.last.system.call.failed." if (-1 == waitpid(child_pid, &child_status, 0) { perror("waitpid"); exit(1); } printf("CT: child %d has terminated\n”, child_pid); } printf("Bye\n"); exit(0); } 12
3 11/12/15
Status Macros Zombies! wait for.child.processes.to.terminate
Terminated1 process1still1consumes1system1resources pid_t waitpid(pid_t pid, int* stat, int ops) Various.tables.maintained.by.OS Suspend.current.process.(i.e..parent).until.child.with.pid ends. A.living.corpse,.half.alive.and.half.dead On.success: Reaping1with wait/waitpid WEXITSTATUS(stat) child exit code Return.pid when.child.terminates. Parent.waits to.reap.child.once.child.terminates Reap.child. Parent.receives.child.exit.status. true if terminated normally WIFEXITED(stat) (called exit or returned from main) Kernel.discards.process. If.stat != NULL,. waitpid saves.termination. reason. where. it. points. What1if1parent1doesn’t1reap? If.any.parent.terminates.without.reaping.a.child,.then.child.will.be.reaped. See.WIFSIGNALED(stat) also:.man&3&waitpid true if terminated by signal by.init process.(pid.==.1) But.in.longYrunning.processes.we.need.explicit reaping WIFSTOPPED(stat) true if paused by signal e.g.,.shells.and.servers 11/12/15 Sean Barker 15
10 11
Option Macros Zombies! wait for.child.processes.to.terminate HCBye waitpidTerminated1 process1examplestill1consumes1system1resources Errorpid_t Gwaitpidchecking(pid_t pid, int* stat, int ops) Various.tables.maintained.by.OS Suspend.current.process.(i.e..parent).until.child.with.pid ends. A.living.corpse,.half.alive.and.half.dead CTBye Check1return1results1of1system1calls1for1errors!1(No.exceptions.) On.success: return immediately if child not voidReaping1 fork_wait()with wait/ waitpid{ Read.documentation.WNOHANG for.return.values. already terminated int child_status; Return.pid when.child.terminates. Parent.waits to.reap.child.once.child.terminates pid_t child_pid == fork(); Use.perrorReap.child.to.report.error,. then.exit. Parent.receives.child.exit.status. If.stat != NULL,. waitpid saves.termination. reason. ifKernel.discards. (child_pidprocess.== 0) { WUNTRACED also wait for paused (stopped) children voidwhere. perror it. points.(char* message) What1if1printf("HC:parent1doesn’t1reap hello from? child\n"); } else { If.any.parent.terminates.without.reaping.a.child,.then.child.will.be.reaped. See.Print."message:. also:.man&3&waitpid reason.that.last.system.call.failed." if (-1 == waitpid(child_pid, &child_status, 0) { by.init process.(pid.==.1) perror("waitpid"); WCONTINUED also wait for resumed children But.in.longexit(1);Yrunning.processes.we.need.explicit reaping } e.g.,.shells.and.servers printf("CT: child %d has terminated\n”, child_pid); Sean Barker 16 } printf("Bye\n"); 10 11 exit(0); } 12 waitpid example HCBye ErrorGchecking 3 CTBye Check1return1results1of1system1calls1for1errors!1(No.exceptions.) void fork_wait() { Read.documentation. for.return.values. int child_status; pid_t child_pid == fork(); Use.perror to.report.error,. then.exit. if (child_pid == 0) { printf("HC: hello from child\n"); void perror(char* message) } else { Print."message:. reason.that.last.system.call.failed." if (-1 == waitpid(child_pid, &child_status, 0) { perror("waitpid"); exit(1); } printf("CT: child %d has terminated\n”, child_pid); } printf("Bye\n"); exit(0); } 12
3 shell:(program(that(runs(other(programs System Call Error Handling
Building(a(Shell Always check return values!
if ((pid = fork()) < 0) {! fprintf(stderr, "fork error: %s\n", strerror(errno));! exit(0);! }
global var
1 5
Sean Barker 17 Unix/Linux( Process(Hierarchy shell program(that(runs(other(programs(on(behalf(of(the(user Basicsh ShellOriginal( DesignUnix(shell((Stephen(Bourne,(AT&T(Bell(Labs,(1977) [0] bash “Bourne?Again”(Shell,(widely(used default(on(most(Unix/Linux/Mac(OS(X(systems others.. . init [1] while (true) { Print command prompt. Daemon Login shell Read command line from user. e.g. httpd Parse command line. If command is built-in, do it. Child Child Child Else fork process to execute command. in child: Execute requested command with execv. (never returns) Grandchild Grandchild in parent: Wait for child to complete. } 6 7
Sean Barker 18 1 terminal ≠(shell Background(vs.(Foreground User(interface( to(shell(and( other(programs. Users(generally( run(one(command( at(a(time Graphical((GUI)( vs.(command?line( (CLI) Type(command,(read(output,(type(another(command
Command@line( terminal( (emulator): Input((keyboard) Some(programs( run(“for(a(long(time” Output((screen) $ emacs fizz. txt # shell stuck until ema cs exi ts.
A( “background”( job(is(a(process(we(don't(want(to(wait(for
$ emacs boom. txt & # em acs ru ns in backg round [1] 9073 # wh ile sh ell i s... $ gdb ./ umbre lla # im mediat ely r eady f or nex t com mand
don't(do(this(with(emacs un l es s( u si n g( X( wi nd o ws( vers i o n 8 9
Managing(Background(Jobs Signals SignalsSignal:(small(message(notifying(a(process(of(event(in(system Shell(waits(for(and(reaps(foreground(jobs. like(exceptions(and(interrupts sent(by(kernel,(sometimes(at(request(of(another(process Background(jobs(become(zombies(when(they(terminate. ID(is(entire(message Shell(might(run(for(a(really(long(time! ID Name Corresponding2Event Default2Action Can2 Kernel(may(run(out(of(memory! Override? fork()( returns(?1(if(per?user( process( quota(exceeded 2 SIGINT Interrupt((Ctrl?C) Te r m i n a t e Yes $ ul imi t -u # b ash sy nta x 9 SIGKILL Kill(process((immediately) Te r m i n a t e No 1024 11 SIGSEGV Segmentation(violation Te r m i n a t e ( & ( D u m p Yes 14 SIGALRM Timer(signal Te r m i n a t e Yes Shell(must(explicitly(reap(background(jobs. 15 SIGTERM Kill(process((politely) Te r m i n a t e Yes One(way:(check/reap(any(completed( background(jobs( before(every(prompt. 17 SIGCHLD Child(stopped(or(terminated Ignore Yes OK,(assuming( foreground( jobs/user(inactivity(are(not(too(long. 18 SIGCONT Continue(stopped(process Continue((Resume) No Another(way:(OS(delivers(signal via(exceptional(control(flow(when(child(ends. 19 SIGSTOP Stop(process((immediately) Stop((Suspend) No OK(to(respond( by(reaping,(but(complicated(concurrency( makes(it(tricky. 20 SIGTSTP Stop(process((politely)(Ctrl-Z) Stop((Suspend) Yes
10 … 12
Sean Barker 19
2 Recap: Segmentation Fault
int a[1000]; main () { a[5000] = 13; }
80483b7: c7 05 60 e3 04 08 0d movl $0xd,0x804e360
User code Kernel code
Excep&on: page fault movl Detect invalid address Signal process
Sean Barker 20 Process Groups
pid=10 pgid=10 Shell
pid=20 Fore- Back- Back- pid=32 pid=40 pgid=20 ground ground pgid=32 ground pgid=40 job job #1 job #2
Background Background process group 32 process group 40 Child Child
pid=21 pid=22 pgid=20 pgid=20 Foreground process group 20
Sean Barker 21
Signal Control Flow
(earlier: signal delivered to process)
(1) Signal received (2) Control passes by process to signal handler Icurr Inext (3) Signal handler runs (4) Signal handler returns to next instruction
Sean Barker 22 Typical Signal Handler Control Flow
Process A Process B
user code (main) Signal delivered Icurr to process A kernel code context switch
user code (main)
kernel code context switch Signal received by process A user code (handler) kernel code I next user code (main)
Sean Barker 23
Reaping in Signal Handler
int main(int argc, char** argv) { int pid;
Signal(SIGCHLD, sigchd_handler); // install signal handler
while (1) { // print prompt, read cmd from user, etc. if ((pid = fork()) == 0) { execve(...); // child: run target program } // parent: wait for child to exit if foreground } return 0; }
void sigchld_handler(int sig) { while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { // reaped child pid } }
Sean Barker 24 Signal Handler as Concurrent Flow
Process A Process A Process B
while (1) handler(){ ; … }
Time
Sean Barker 25
Job List Concurrency (1)
int main(int argc, char** argv) { int pid;
Signal(SIGCHLD, sigchd_handler); initjobs(); // initialize job list Concurrent job while (1) { list modification! if ((pid = fork()) == 0) { execve(...); } addjob(pid); // add child to job list } return 0; }
void sigchld_handler(int sig) { while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { deletejob(pid); // delete child from job list } }
Sean Barker 26 Job List Concurrency (2)
int main(int argc, char** argv) { int pid; Signal(SIGCHLD, sigchd_handler); Parent/child initjobs(); race condition! sigset_t mask; // signal bit vector sigemptyset(&mask); // clear all bits sigaddset(&mask, SIGCHLD); // set SIGCHILD bit while (1) { if ((pid = fork()) == 0) { execve(...); } sigprocmask(SIG_BLOCK, &mask, NULL); // block SIGCHLD addjob(pid); // add child to job list sigprocmask(SIG_UNBLOCK, &mask, NULL); // unblock SIGCHLD } return 0; }
void sigchld_handler(int sig) { while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { deletejob(pid); // delete child from job list } }
Sean Barker 27
Job List Concurrency (3)
int main(int argc, char** argv) { int pid; Signal(SIGCHLD, sigchd_handler); initjobs(); sigset_t mask; // signal bit vector sigemptyset(&mask); // clear all bits sigaddset(&mask, SIGCHLD); // set SIGCHILD bit while (1) { sigprocmask(SIG_BLOCK, &mask, NULL); // block SIGCHLD if ((pid = fork()) == 0) { // unblock in child (inherited from parent) sigprocmask(SIG_UNBLOCK, &mask, NULL); execve(...); } addjob(pid); // add child to job list sigprocmask(SIG_UNBLOCK, &mask, NULL); // unblock SIGCHLD } return 0; }
Sean Barker 28 Useful System Calls
• fork – Create a new process • execve – Run a new program • kill – Send a signal • waitpid – Wait for and/or reap child process • setpgid – Set process group ID • sigsuspend – Wait until signal received • sigprocmask – Block or unblock signals • sigemptyset – Create empty signal set • sigfillset – Add every signal number to set • sigaddset – Add signal number to set • sigdelset – Delete signal number from set
Sean Barker 29
Threads
Sean Barker 30 Thread Example
/* ! * hello.c - Pthreads "hello, world" program ! */! Thread attributes Thread ID ! (usually NULL) void* thread(void* vargp); ! ! int main() {! ! Thread routine pthread_t tid; ! pthread_create(&tid, NULL, thread, NULL); ! pthread_join(tid, NULL); ! Thread arguments exit(0); ! (void *p) }! hello.c
Return value (void **p) void* thread(void* vargp) { /* thread routine */! printf("Hello, world!\n");! return NULL; ! } hello.c
Sean Barker 31