Process Management II CS 351: Systems Programming Michael Saelee - - PowerPoint PPT Presentation

process management ii
SMART_READER_LITE
LIVE PREVIEW

Process Management II CS 351: Systems Programming Michael Saelee - - PowerPoint PPT Presentation

Process Management II CS 351: Systems Programming Michael Saelee <lee@iit.edu> 1 Computer Science Science Recall: all processes turn into zombies upon termination - no longer runnable, but still tracked by OS kernel 2 Computer


slide-1
SLIDE 1

Process Management II

CS 351: Systems Programming Michael Saelee <lee@iit.edu>

1

slide-2
SLIDE 2

Computer Science Science

Recall: all processes turn into zombies upon termination

  • no longer runnable, but still tracked by

OS kernel

2

slide-3
SLIDE 3

Computer Science Science

§Reaping Processes (& Synchronization)

3

slide-4
SLIDE 4

Computer Science Science

All processes are responsible for reaping their own (immediate) children

4

slide-5
SLIDE 5

Computer Science Science

So what happens if we don’t?

5

slide-6
SLIDE 6

Computer Science Science

$ ./a.out & Parent pid = 7254 $ ps -g 7254 PID STAT TT STAT TIME COMMAND 7254 S s003 S 0:00.01 ./a.out 7255 Z s003 Z 0:00.00 (a.out) 7256 Z s003 Z 0:00.00 (a.out) 7257 Z s003 Z 0:00.00 (a.out) int main() { int i; for (i=0; i<3; i++) { if (fork() == 0) exit(0); } printf("Parent pid = %d\n", getpid()); while (1) ; /* non-terminating parent */ }

6

slide-7
SLIDE 7

Computer Science Science

$ ./a.out Parent pid = 7409 $ ps -g 7409 PID STAT TT STAT TIME COMMAND int main() { int i; for (i=0; i<3; i++) { if (fork() == 0) exit(0); } printf("Parent pid = %d\n", getpid()); return 0; /* (parent exits) */ }

7

slide-8
SLIDE 8

Computer Science Science

Q: How to kill a zombie? A: By shooting it in the head! (i.e., terminating its parent process)

8

slide-9
SLIDE 9

Computer Science Science

Orphaned processes (i.e., with terminated parents) are adopted by the OS kernel … and the kernel always reaps its children

9

slide-10
SLIDE 10

Computer Science Science

It is especially important for long-running processes to reap their children (why?)

10

slide-11
SLIDE 11

Computer Science Science

int main() { int i; for (i=0; i<3; i++) { if (fork() == 0) exit(0); } printf("Parent pid = %d\n", getpid()); return 0; /* (parent exits) */ }

Q: who reaps the parent??

11

slide-12
SLIDE 12

Computer Science Science

The Shell! A:

12

slide-13
SLIDE 13

Computer Science Science

int main() { printf("My parent's pid = %d\n", getppid()); printf("My own pid = %d\n", getpid()); return 0; /* terminate -> zombie */ } $ ./a.out My parent's pid = 7600 My own pid = 7640 $ ps PID STAT TT STAT TIME COMMAND 7600 Ss s005 Ss 0:28.32 -bash

The Shell! (how does it do it?)

13

slide-14
SLIDE 14

Computer Science Science

pid_t reap(int *stat_loc); (I wish)

14

slide-15
SLIDE 15

Computer Science Science

pid_t wait(int *stat_loc);

15

slide-16
SLIDE 16

Computer Science Science

pid_t wait(int *stat_loc); when called by a process with ≥ 1 children:

  • waits (if needed) for a child to terminate
  • reaps a zombie child (if ≥ 1 zombified

children, arbitrarily pick one)

  • returns reaped child’s pid and exit status

info via pointer (if non-NULL)

16

slide-17
SLIDE 17

Computer Science Science

pid_t wait(int *stat_loc); when called by a process with no children:

  • return -1 immediately & populate errno

17

slide-18
SLIDE 18

Computer Science Science

$ ./a.out & Parent pid = 7505 Child pid = 7506 $ ps -g 7505 PID STAT TT STAT TIME COMMAND 7505 R s003 R 0:00.05 ./a.out int main() { pid_t cpid; if (fork() == 0) exit(0); /* child -> zombie */ else cpid = wait(NULL); /* reaping parent */ printf("Parent pid = %d\n", getpid()); printf("Child pid = %d\n", cpid); while (1) ; }

18

slide-19
SLIDE 19

Computer Science Science

void fork9() { if (fork() == 0) { printf("HC: hello from child\n"); } else { printf("HP: hello from parent\n"); wait(NULL); printf("CT: child has terminated\n"); } printf("Bye\n"); }

19

slide-20
SLIDE 20

Computer Science Science

HP CT HC Bye Bye HP HC CT Bye Bye HP HC Bye CT Bye HC Bye HP CT Bye HC HP Bye CT Bye

A B C D E

void fork9() { if (fork() == 0) { printf("HC: hello from child\n"); } else { printf("HP: hello from parent\n"); wait(NULL); printf("CT: child has terminated\n"); } printf("Bye\n"); }

20

slide-21
SLIDE 21

Computer Science Science

wait allows us to synchronize one process with events (e.g., termination) in another

21

slide-22
SLIDE 22

Computer Science Science

int main() { if (fork() == 0) { if (fork() == 0) { printf("3"); } else { wait(NULL); printf("4"); } } else { if (fork() == 0) { printf("1"); exit(0); } printf("2"); } printf("0"); return 0; }

  • A. 2030401
  • B. 1234000
  • C. 2300140
  • D. 2034012
  • E. 3200410
  • F. 3401200

22

slide-23
SLIDE 23

Computer Science Science

int main() { int stat; if (fork() == 0) exit(1); else wait(&stat); printf("%d\n", stat); return 0; } $ ./a.out 256

23

slide-24
SLIDE 24

Computer Science Science

“status” reported by wait is more than just the exit status of the child; e.g.,

  • normal/abnormal termination
  • termination cause
  • exit status

24

slide-25
SLIDE 25

Computer Science Science

/* macros */ WIFEXITED(status) /* exited normally? */ WEXITSTATUS(status) /* if so, exit status */ WIFSTOPPED(status) /* process stopped? */ WIFSIGNALED(status) /* process signaled? */ WTERMSIG(status) /* if so, signal number */ /* prints information about a signal */ void psignal(unsigned sig, const char *s);

25

slide-26
SLIDE 26

Computer Science Science

int main() { int stat; if (fork() == 0) exit(1); else wait(&stat); if (WIFEXITED(stat)) printf("Exit status: %d\n", WEXITSTATUS(stat)); else if (WIFSIGNALED(stat)) psignal(WTERMSIG(stat), "Exit signal"); return 0; } $ ./a.out Exit status: 1

26

slide-27
SLIDE 27

Computer Science Science

int main() { int stat; if (fork() == 0) *(int *)NULL = 0; else wait(&stat); if (WIFEXITED(stat)) printf("Exit status: %d\n", WEXITSTATUS(stat)); else if (WIFSIGNALED(stat)) psignal(WTERMSIG(stat), "Exit signal"); return 0; } $ ./a.out Exit signal: Segmentation fault

27

slide-28
SLIDE 28

Computer Science Science

void fork10() { int i, stat; pid_t pid[5]; for (i=0; i<5; i++) if ((pid[i] = fork()) == 0) { sleep(1); exit(100+i); } for (i=0; i<5; i++) { pid_t cpid = wait(&stat); if (WIFEXITED(stat)) printf("Child %d terminated with status %d\n", cpid, WEXITSTATUS(stat)); } } Child 8590 terminated with status 101 Child 8589 terminated with status 100 Child 8593 terminated with status 104 Child 8592 terminated with status 103 Child 8591 terminated with status 102

28

slide-29
SLIDE 29

Computer Science Science

/* explicit waiting -- i.e., for a specific child */ pid_t waitpid(pid_t pid, int *stat_loc, int options); /** Wait options **/ /* return 0 immediately if no terminated children */ #define WNOHANG 0x00000001 /* also report info about stopped children (and others) */ #define WUNTRACED 0x00000002

29

slide-30
SLIDE 30

Computer Science Science

void fork11() { int i, stat; pid_t pid[5]; for (i=0; i<5; i++) if ((pid[i] = fork()) == 0) { sleep(1); exit(100+i); } for (i=0; i<5; i++) { pid_t cpid = waitpid(pid[i], &stat, 0); if (WIFEXITED(stat)) printf("Child %d terminated with status %d\n", cpid, WEXITSTATUS(stat)); } } Child 8704 terminated with status 100 Child 8705 terminated with status 101 Child 8706 terminated with status 102 Child 8707 terminated with status 103 Child 8708 terminated with status 104

30

slide-31
SLIDE 31

Computer Science Science

int main() { int stat; pid_t cpid; if (fork() == 0) { printf("Child pid = %d\n", getpid()); sleep(3); exit(1); } else { /* use with -1 to wait on any child (with options) */ while ((cpid = waitpid(-1, &stat, WNOHANG)) == 0) { sleep(1); printf("No terminated children!\n"); } printf("Reaped %d with exit status %d\n", cpid, WEXITSTATUS(stat)); } } Child pid = 8885 No terminated children! No terminated children! No terminated children! Reaped 8885 with exit status 1

31

slide-32
SLIDE 32

Computer Science Science

Recap:

  • fork: create new (duplicate) process
  • exit: terminate process
  • wait: reap terminated (zombie) process

32

slide-33
SLIDE 33

Computer Science Science

§Running new programs (within processes)

33

slide-34
SLIDE 34

Computer Science Science

/* the "exec family" of syscalls */ int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]);

34

slide-35
SLIDE 35

Computer Science Science

Execute a new program within the current process context

35

slide-36
SLIDE 36

Computer Science Science

Complements fork (1 call → 2 returns):

  • when called, exec (if successful)

never returns!

  • starts execution of new program

36

slide-37
SLIDE 37

Computer Science Science

int main() { execl("/bin/echo", "/bin/echo", "hello", "world", (void *)0); printf("Done exec-ing...\n"); return 0; } $ ./a.out hello world

37

slide-38
SLIDE 38

Computer Science Science

int main() { printf("About to exec!\n"); sleep(1); execl("./execer", "./execer", (void *)0); printf("Done exec-ing...\n"); return 0; } $ gcc execer.c -o execer $ ./execer About to exec! About to exec! About to exec! About to exec! ...

38

slide-39
SLIDE 39

Computer Science Science

int main () { if (fork() == 0) { execl("/bin/ls", "/bin/ls", "-l", (void *) 0); exit(0); /* in case exec fails */ } wait(NULL); printf("Command completed\n"); return 0; } $ ./a.out

  • rwxr-xr-x 1 lee staff 8880 Feb 8 01:51 a.out
  • rw-r--r-- 1 lee staff 267 Feb 8 01:51 demo.c

Command completed

39

slide-40
SLIDE 40

Computer Science Science

Interesting question: Why are fork & exec separate syscalls?

/* i.e., why not: */ fork_and_exec("/bin/ls", ...)

40

slide-41
SLIDE 41

Computer Science Science

A1: we might really want to just create duplicates of the current process (e.g.?)

41

slide-42
SLIDE 42

Computer Science Science

A2: we might want to replace the current program without creating a new process

42

slide-43
SLIDE 43

Computer Science Science

A3 (more subtle): we might want to “tweak” a process before running a program in it

43