State Only one process can be running on a uniprocessor The scheduler decides rrunniing Processes which of the ready processes to run.

bllocckked orr Creating and using multiple processes rreadyy sslleepiing

A process is ready if it A process is blocked if it could use the CPU immediately. waiting for an event (I/O, )

12 13

Fork example

• The fork creates a duplicate of the currently int main () running program. { • The duplicate () and the original (parent pid_t pid; process) both proceed from the point of the fork with pid = fork(); exactly the same data. if (pid < 0) { • The only difference is the return value from the fork call. perror("fork()"); } else if (pid > 0) { Process printf("parent\n"); A } else { /* pid == 0 */ Process printf("child\n"); A fork } return 0; Process Ch 5.2 } A1

14 15 Fork: PIDs and PPIDs When fork() fails

• System call: int fork(void) • There is a limit to the maximum number – If fork() succeeds it returns the child PID to the parent and returns 0 to the child; of processes a user can create. – If fork() fails, it returns -1 to the parent (no child • Once this limit is reached, subsequent is created) and sets errno calls to fork() return -1. • Related system calls: – int getpid() – returns the PID of current process – int getppid() – returns the PID of (ppid of 1 is 1)

16 17

fork() properties Fork example • Properties of parent inherited by child: int i; pid_t pid; – UID, GID – controlling terminal i = 5; – CWD, root directory printf("%d\n", i); – signal mask, environment, resource limits pid = fork(); – shared memory segments • Differences between parent and child if (pid > 0) i = 6; /* only parent gets here */ – PID, PPID, return value from fork() else if (pid == 0) – pending alarms cleared for child i = 4; /* only child gets here */ – pending signals are cleared for child printf("%d\n", i);

18 19 Fork Example PID/PPID Example Original process (parent) Child process #include #include int i; pid_t pid; int i; pid_t pid; #include i = 5; i = 5; int main() { printf("%d\n", i); printf("%d\n", i); pid_t pid; /* prints 5 */ printf("ORIG: PID=%d PPID=%d\n", pid = fork(); pid = fork(); getpid(), getppid()); /* pid == 0 */ /* pid == 677 */ pid = fork(); if (pid > 0) if (pid > 0) if (pid > 0) i = 6; i = 6; printf("PARENT: PID=%d PPID=%d\n", else (pid == 0) else if (pid = = 0) getpid(), getppid()); i = 4; i = 4; else if (pid == 0) printf("%d\n", i); printf("%d\n", i); printf("CHILD: PID=%d PPID=%d\n", /* prints 6 */ /* prints 4 */ getpid(), getppid()); return(0); 20 } 21

Ch 5.7 Process Termination () Ch 5.6 • : • System call to wait for a child – a process whose parent is the process (PID 1) – pid_t wait(int *status) because its original parent died before it did. • A process that calls wait() can: • Terminating a process: () – block (if all of its children are still running) • Every normal process is a child of some parent, a terminating process sends its parent – return immediately with the termination status of a child (if a child has terminated and is waiting for its a SIGCHLD signal and waits for its termination status to be fetched) termination status to be accepted. – return immediately with an error (if it doesn’t have • The Bourne shell stores the termination code any child processes.) of the last command in $?.

22 23 Zombies wait and waitpid • wait() can • A : – block – return with termination status – a process that is “waiting” for its parent to accept its return code – return with error – a parent accepts a child’s return code by • If there is more than one child wait() returns executing wait() on termination of any children – shows up as Z in –a • waitpid can be used to wait for a specific child – A terminating process may be a (multiple) pid. parent; the kernel ensures all of its children • waitpid also has an option to block or not to are orphaned and adopted by init. block

24 25

wait and waitpid Example of wait • waitpid has an option to block or not to block #include • pid_t waitpid(pid, &status, option); #include int main() { – if pid == -1 Æ wait for any child int status; Æ – if option == WNOHANG non-blocking if(fork() == 0) exit(7); /*normal*/ – if option == 0 Æ blocking wait(&status); prExit(status); if(fork() == 0) abort(); /*SIGABRT*/ • waitpid(-1, &status, 0); wait(&status); prExit(status); is equivalent to wait(&status); if(fork() == 0) status /= 0; /*FPE*/ wait(&status); prExit(status); return 0;

26 } 27 Ch 5.3 prExit.

#include • The exec system call replaces the program being run void prExit(int status) { by a process by a different one. if(WIFEXITED( status ) ) • The new program starts executing from the printf("normal termination\n"); beginning. else if(WIFSTOPPED( status )) • On success, exec never returns, on failure, exec printf("child stopped, signal no.= %d\n", returns -1. WSTOPSIG(status)); else if(WIFSIGNALED( status ) ) Process A exec("Y"); Process A printf("abnormal termination, " running running "signal no.= %d\n", WTERMSIG(status)); program X program Y }

28 29

Exec example exec properties Program X int i = 5; • New process inherits from calling printf("%d\n", i); process: exec("Y"); – PID and PPID, real UID, GID printf("%d\n", i); – controlling terminal – CWD, root directory, resource limits Program Y – pending signals printf("hello\n"); – pending alarms

30 31 exec() Processes and File Descriptors • Six versions exec(): execl(char *, char *arg0, …, (char *)NULL); • File descriptors are handles to open files. execv(char *path, char *argv[]); • They belong to processes not programs. execle(char *path, char *arg0, …,(char *)NULL, • They are a process’s link to the outside world. char *envp[]); execve(char *pathname, char *argv[], char *envp[]); execlp(char *file, char *arg0, …,(char *)NULL); execvp(char *file, char *argv[]);

32 33

FDs preserved across fork and exec Initializing

init init init init init Prroccessss A Prroccessss B rrunniing fork fd=8 prrogrram X exec exec exec fd=3 init getty login tcsh fork() /u/krueger/bar exec("Y"); /u/krueger/foo Time fd=8 fd=3 • See “top”, “ps –aux” to see what’s running Process C Prroccessss A Process C • The only way to create a new process is to rrunniing program Y duplicate an existing process. Therefore the program Y ancestor of all processes is init with pid = 1 Ch 5.5 • The only way to run a program is with exec 34 35 How csh runs commands How csh runs

csh csh csh Prroccessss rrunniing sshellll duplicate: PID 34 fork() fork fork PID 34 Chiilld exec exec process running shell csh date csh ls process running shell Parrentt PIID 35 Time prroccessss rrunniing sshellll differentiate: PIID 34 exec() • When a command is typed, csh forks and then execs wait for child: Chiilld the typed command. wait() prroccessss rrunniing prrogrram Parrentt PIID 35 • After the fork, file descriptors 0, 1, and 2 still refer to prroccessss rrunniing sshellll terminate: stdin, stdout, and stderr in the new process. PIID 34 exit() • By convention, the executed program will use these Chiilld process terminated descriptors appropriately. signal process terminated PIID 35

36 37