Control Flow

CPU

Sean Barker 1

Physical Control Flow

Physical control flow inst1 inst Time 2 inst3 …

instn

Sean Barker 2

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 '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 (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 • 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