Changelog Changes made in this version not seen in fjrst lecture: 24 Jan 2019: wait: return value for WNOHANG when process not done is 0, not -1 24 Jan 2019: reading a fjxed amount: add check for amount_read = 0 0
POSIX API 2 1
last time context switch (fjnish) POSIX fork exec waitpid 2
POSIX process management essential operations process information: getpid process creation: fork running programs: exec* also posix_spawn (not widely supported), … waiting for processes to fjnish: waitpid (or wait ) process destruction, ‘signaling’: exit , kill 3
POSIX process management essential operations process information: getpid process creation: fork running programs: exec* also posix_spawn (not widely supported), … process destruction, ‘signaling’: exit , kill 4 waiting for processes to fjnish: waitpid (or wait )
wait/waitpid pid_t waitpid(pid_t pid, int *status, int options) wait for a child process (with pid= pid ) to fjnish sets *status to its “status information” options? see manual page (command man waitpid ) 0 — no options WNOHANG — return 0 rather than hanging if process not yet done 5 pid=-1 → wait for any child process instead
wait/waitpid pid_t waitpid(pid_t pid, int *status, int options) wait for a child process (with pid= pid ) to fjnish sets *status to its “status information” options? see manual page (command man waitpid ) 0 — no options WNOHANG — return 0 rather than hanging if process not yet done 5 pid=-1 → wait for any child process instead
exit statuses int main() { return 0; */ } 6 /* or exit(0);
waitpid example #include <sys/wait.h> ... child_pid = fork(); if (child_pid > 0) { int status; waitpid(child_pid, &status, 0); ... 7 /* Parent process */ } else if (child_pid == 0) { /* Child process */
the status %d\n", W* macros to decode it } ... WTERMSIG(status), SIGINT); %d)\n", signal causes (control-C %d signal by #include <sys/wait.h> printf("killed WEXITSTATUS(status)); 8 ... called exit waitpid(child_pid, &status, 0); if (WIFEXITED(status)) { or with printf("main returned ␣ ␣ ␣ ␣ ␣ ␣ } else if (WIFSIGNALED(status)) { ␣ ␣ ␣ ␣ ␣ ␣ ␣ } else { “status code” encodes both return value and if exit was abnormal
the status %d\n", W* macros to decode it } ... WTERMSIG(status), SIGINT); %d)\n", signal causes (control-C %d signal by #include <sys/wait.h> printf("killed WEXITSTATUS(status)); 8 ... called exit waitpid(child_pid, &status, 0); if (WIFEXITED(status)) { or with printf("main returned ␣ ␣ ␣ ␣ ␣ ␣ } else if (WIFSIGNALED(status)) { ␣ ␣ ␣ ␣ ␣ ␣ ␣ } else { “status code” encodes both return value and if exit was abnormal
aside: signals signals are a way of communicating between processes they are also how abnormal termination happens wait’s status will tell you when and what signal killed a program constants in signal.h SIGINT — control-C SIGTERM — kill command (by default) SIGSEGV — segmentation fault SIGBUS — bus error SIGABRT — abort() library function … 9
waiting for all children #include <sys/wait.h> ... while ( true ) { if (errno == ECHILD) { break ; } } } 10 pid_t child_pid = waitpid( − 1, &status, 0); if (child_pid == (pid_t) − 1) { /* no child process to wait for */ } else { /* some other error */ /* handle child_pid exiting */
‘waiting’ without waiting #include <sys/wait.h> ... pid_t return_value = waitpid(child_pid, &status, WNOHANG); if (return_value == (pid_t) 0) { } else { } 11 /* child process not done yet */ } else if (child_pid == (pid_t) − 1) { /* error */ /* handle child_pid exiting */
parent and child processes every process (but process id 1) has a parent process ( getppid() ) this is the process that can wait for it creates tree of processes: 12
parent and child questions… what if parent process exits before child? child’s parent process becomes process id 1 (typically called init ) what if parent process never waitpid()/wait() s for child? child process stays around as a “zombie” can’t reuse pid in case parent wants to use waitpid() what if non-parent tries to waitpid() for child? waitpid fails 13
typical pattern } } … main() { … } … waitpid(pid,…); } else if (pid > 0) { … exec…(…); if (pid == 0) { pid = fork(); … … pid = fork(); waitpid(pid,…); } else if (pid > 0) { … exec…(…); if (pid == 0) { pid = fork(); … } … waitpid(pid,…); } else if (pid > 0) { … exec…(…); if (pid == 0) { 14
multiple processes? while (...) { pid = fork(); if (pid == 0) { exec ... pids.push_back(pid); } } for (pid_t pid : pids) { waitpid(pid, ...); ... } 15 } else if (pid > 0) { /* retrieve exit statuses in order */
multiple processes? while (...) { pid = fork(); if (pid == 0) { exec ... pids.push_back(pid); } } handleProcessFinishing(pid); } 16 } else if (pid > 0) { /* retrieve exit statuses as processes finish */ while ((pid = waitpid( − 1, ...)) != − 1) {
POSIX process management essential operations process information: getpid process creation: fork running programs: exec* also posix_spawn (not widely supported), … waiting for processes to fjnish: waitpid (or wait ) process destruction, ‘signaling’: exit , kill 17
shell allow user (= person at keyboard) to run applications user’s wrapper around process-management functions upcoming homework — make a simple shell 18
aside: shell forms POSIX: command line you have used before also: graphical shells e.g. OS X Finder, Windows explorer other types of command lines? completely difgerent interfaces? 19
some POSIX command-line features searching for programs (not in assignment) running in background ./someprogram & redirection: ./someprogram >output.txt ./someprogram <input.txt pipelines: ./someprogram | ./somefilter 20 ls -l ≈ /bin/ls -l make ≈ /usr/bin/make
some POSIX command-line features searching for programs (not in assignment) running in background ./someprogram & redirection: ./someprogram >output.txt ./someprogram <input.txt pipelines: ./someprogram | ./somefilter 21 ls -l ≈ /bin/ls -l make ≈ /usr/bin/make
searching for programs POSIX convention: PATH environment variable example: /home/cr4bd/bin:/usr/bin:/bin checked in order one way to implement: [pseudocode] for (directory in path) { } 22 execv(directory + "/" + program_name, argv);
some POSIX command-line features searching for programs (not in assignment) running in background ./someprogram & redirection: ./someprogram >output.txt ./someprogram <input.txt pipelines: ./someprogram | ./somefilter 23 ls -l ≈ /bin/ls -l make ≈ /usr/bin/make
running in background $ ./long_computation >tmp.txt & [1] 4049 $ ... [1]+ Done ./long_computation > tmp.txt $ cat tmp.txt the result is ... & — run a program in “background” initially output PID (above: 4049) print out after terminated one way: use waitpid with option saying “don’t wait” 24
some POSIX command-line features searching for programs (not in assignment) running in background ./someprogram & redirection: ./someprogram >output.txt ./someprogram <input.txt pipelines: ./someprogram | ./somefilter 25 ls -l ≈ /bin/ls -l make ≈ /usr/bin/make
shell redirection ./my_program ... <input.txt : run ./my_program ... but use input.txt as input like we copied and pasted the fjle into the terminal echo foo >output.txt : runs echo foo , sends output to output.txt like we copied and pasted the output into that fjle (as it was written) 26
exec preserves open fjles the process control block discarded old memory not changed! copy arguments new stack, heap, … executable fjle loaded from memory … user regs … fd 1: … fd 0: (terminal …) open fjles user memory kernel stack ecx=133 init. val. , … eax=42 init. val. , 27
exec preserves open fjles the process control block discarded old memory not changed! copy arguments new stack, heap, … executable fjle loaded from memory … user regs … fd 1: … fd 0: (terminal …) open fjles user memory kernel stack ecx=133 init. val. , … eax=42 init. val. , 27
exec preserves open fjles the process control block discarded old memory not changed! copy arguments new stack, heap, … executable fjle loaded from memory … user regs … fd 1: … fd 0: (terminal …) open fjles user memory kernel stack ecx=133 init. val. , … eax=42 init. val. , 27
exec preserves open fjles the process control block discarded old memory not changed! copy arguments new stack, heap, … executable fjle loaded from memory … user regs … fd 1: … fd 0: (terminal …) open fjles user memory kernel stack ecx=133 init. val. , … eax=42 init. val. , 27
fork copies open fjles eax=420, copy copy child process control block … … fd 1: … fd 0: … open fjles user memory kernel stack ecx=133, … user regs user regs memory parent process control block … … fd 1: … fd 0: … open fjles user memory kernel stack ecx=133, … eax=42 child (new) pid , 28
Recommend
More recommend