213 RecitationJiri [email protected] shell hints• Executing programs• Understanding process tree• Reap all child processes• Avoid race hazard• I/O redirectionExecute programint execve(const char *fname, char *const argv[], char *const envp[]);Examples:execve(“/bin/ls”, NULL, NULL);execve(“./mytest”, argv, envp);Process tree for a shellFore-groundjobBack-groundjob #1Back-groundjob #2ShellChild Childpid=10pgid=10Foregroundprocess group 20Backgroundprocess group 32Backgroudprocess group 40pid=20pgid=20pid=32pgid=32pid=40pgid=40pid=21pgid=20pid=22pgid=20Each job has a unique process group idint setpgid(pid_t pid, pid_t pgid);setpgid(0, 0);Process tree for a shellFore-groundjobBack-groundjob #1Back-groundjob #2tshChild Childpid=10pgid=10Foregroundprocess group 20Backgroundprocess group 32Backgroudprocess group 40pid=20pgid=20pid=32pgid=32pid=40pgid=40pid=21pgid=20pid=22pgid=20Foreground jobreceives SIGINT, SIGTSTP,when you type ctrl-c, ctrl-zForward signalsint kill(pid_t pid, int sig)pid > 0: send sig to specified processpid = 0: send sig to all processes in same grouppid < -1: send sig to group -pidReaping child processwaitpid(pid_t pid, int *status, int options)pid: wait for child process with pid (process id or group id)-1: wait for any child processstatus: tell why child terminatedoptions:WNOHANG: return immediately if no children zombiedWUNTRACED: report status of terminated or stopped childrenIn Lab 4, use:waitpid(-1, &status, WNOHANG|WUNTRACED)In sigchld_handler(): while ((c_pid = waitpid(…)) > 0)Reaping child processint status;waitpid(pid, &status, WNOHANG|WUNTRACED)What to check in sigchld_handler: WIFEXITED(status): child exited normally (the child finished, and quit normally on its own) WEXITSTATUS(status): returns code when child exits WIFSIGNALED(status): child exited because a signal is not caught (SIGINT, or typing CTRL-C) WTERMSIG(status): gives the terminating signal number WIFSTOPPED(status): child is stopped by the receipt of a signal (SIGSTOP, or typing CTRL-Z) WSTOPSIG(status): gives the stop signal numberReaping child processWhere to put waitpid(…)? eval() vs. sigchld_handler()In sigchld_handler(): for botheval() should wait for a fg jobBusy wait for a fg jobIn eval():if(fork() != 0) { /* parent */ addjob(…); while(fg process still alive){ /* do nothing */ }}SleepIn eval():if(fork() != 0) { /* parent */ addjob(…); while(fg process still alive){ sleep(1); }}Race hazardA data structure is shared by twopieces of code that can runconcurrentlyDifferent behaviors of programdepending upon how the scheduleinterleaves the execution of code.An example of race hazardsigchld_handler() { while ((pid = waitpid(…)) > 0){ deletejob(pid); }}eval() { pid = fork(); if(pid == 0) { /* child */ execve(…); } /* parent */ /* signal handler may run BEFORE addjob()*/ addjob(…);}ShellSignal Handler Childfork()addjob()execve()exit()sigchld_handler()deletejob()timeShellSignal Handler Childfork()execve()exit()sigchld_handler()deletejob()timeaddjob()Job added to job list after the signal handler tried to delete it!Solution: blocking signalssigchld_handler() { pid = waitpid(…); deletejob(pid);}eval() { sigprocmask(SIG_BLOCK, …) pid = fork(); if(pid == 0) { /* child */ sigprocmask(SIG_UNBLOCK, …) execve(…); } /* parent */ /* signal handler might run BEFORE addjob() */ addjob(…); sigprocmask(SIG_UNBLOCK, …)}I/O redirection Do it before call execve() in child processeval() { pid = fork(); if(pid == 0) { /* child */ /* Redirect I/O */ if (redirect_input) dup2(…);/* redirect STDIN */ if (redirect_output) dup2(…);/* redirect STDOUT */ execve(…); } addjob(…);}dup2(int oldfd, int newfd) Covered in Chapter 11oldfd: old file descriptornewfd: new file descriptor Dup2 makes newfd be a copy of the oldfdSome examples:Get input from in_fd instead of standard inputdup2(in_fd, STDIN_FILENO);Print output to out_fd instead of standard outputdup2(out_fd, STDOUT_FILENO);Reminders Some important system calls: fork, execve, waitpid, sigprocmask, setpgid, kill Check man pages for details about system calls man 2 kill Check return values of all system calls STEP by STEP Test your shell by typing commands first Each trace worth the same (work on easy ones first!) Start
View Full Document