Today: Processes OS: A layer of software between app and h/w that 1) hides h/w details 2) manages h/w resources Process: an instance of a running program * Processes execute in unprivileged mode; OS in privileged mode 3 h/w mechanism to go from unprivileged --> privileged - exceptions - traps - interrupts * (traps) Process asks for OS assistance in the form of syscall * (exceptions) Process encounter exceptions during execution; exceptions "call into" kernel code * (interrupts) Multiprocessing & context switch Multiprocessing goal: run many processes simulataneously Why: - play music / browse the web while running labs Many processes running on the computer: stack stack heap heap data data code code saved saved memory: registers registers CPU state:registers rip: next instruction of P1 Switch from P1 to P2: * save rip & other registers in P1's PCB * load saved registers of P2 P1 User code kernel code P2 user code | | ___timer interrupt_________> decide it's P2's turn save P1 state load P2 iret ----------------------------> | <---- timer interrupt-------| P1 & P2 executes at disjoint intervals of time But, as timer interrupt is frequent (per 10 ms), P1 & P2 appear to be executing concurrently. * Creating and killing processes * How to create a new process? One process creates another process via the fork() syscall - all processes are created by some other processes. the first process, called init, is created by OS. - the process of your lab program is created by the shell program. * The fork() syscall - creates a new (child) process (almost completely) identical to the parent - same code, data, heap, stack, register state except different return values of the fork() syscall - returns child process id in parent process - returns zero in child process - "called once, returned twice" - child process inherits parent's open file descriptors void main() { pid_t pid = fork(); if (pid == 0) { printf("In child\n"); }else{ //pid < 0 if fork() failed printf("In parent, child pid=%d\n", pid); } } Draw picture one process, about to execute fork() make another copy of the process, show they process in different code path afterwards Notes on fork() * execution of parent and child processes are concurrent / interleaving is non-determinstic both are possible: In child In parent,... or In parent,.. In child * Duplicate but separate address space add int x = 0; x++; in child x--; in parent Another example: void main() { 1: printf("hello\n"); 2: fork(); 3: printf("world\n"); 4: fork(); 5: printf("Bye\n"); } How many processes are created? L1 --> L2 --> L3 --->L4---> L5 | +-----> L5 | +----> L3 ---->L4---> L5 + ---->L5 What are the possible printouts? hello hello world world world bye bye bye bye world bye bye bye bye both above are possible, and others... how about hello bye world world bye bye bye? Another example: void main() { 1:printf("hello\n"); 2:if (fork() == 0) { 3: printf("big\n"); 4: if (fork() == 0) { 5: printf("world\n"); } } 6: printf("Bye\n"); } L1--->L2---> L3 --->L4 ---> L5 ---> L6 | +----> L6 | +----> L6 hello big world bye bye bye hello bye big bye world bye infeasible: hello bye big bye bye world * wait: synchronize with child processes int waitpid(pid_t pid, int *child_status, int options) wait() to wait for any child, not a specific one add line: else {waitpid(pid, &status, 0)} good practice for parent to wait (reap) child otherwise, the state maintained in OS about child cannot be freed --> child becomes zombie what about zombies: if parent dies, then the first process (init) reaps its (zombie) children if parent does not die, then zombies lie around * execv load program in the current process int execv(char *filename, char *argv[]) - *overwrites* code, data, stack (retains PID, opened files) - called once, never returns