1 / 23

Shell Lab: Process IDs, Signals, Reminders, Quiz

This shell lab covers topics such as process IDs, signals, reminders, and a quiz. It includes information on creating and managing process groups, sending signals to processes, and reaping terminated child processes.

marybarker
Download Presentation

Shell Lab: Process IDs, Signals, Reminders, Quiz

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Outline Shell Lab Processes Signals Reminders Quiz today Shell Lab: Due Next Thursday TA: Jernej Barbic Modified from: Kun Gao’s and Minglong Shao’s recitations, Spring 2005,Fall 2004 Recitation #8, Section F, 15-213, Sp 06

  2. Process IDs & process groups • A process has its own, unique process ID • pid_t getpid(); • A process belongs to exactly one process group • pid_t getpgrp(); • A new process belongs to which process group? • Its parent’s process group • Make a new process group for myself and my children: • setpgid(0, 0);

  3. Process & concurrency • int fork(void) • Create a new process identical to parent process • Return 0 to child process • Return child’s pid to the parent process • Any scheduling order of processes is possible!! • Unless code uses explicit synchronization • Context switching can happen at any point

  4. Lab 5 • A tiny shell with job control & I/O redirection • Key points: • Reap all child processes • Handle SIGCHLD, SIGTSTP, SIGINT • Avoid race hazards

  5. How to Send Signals • To a single process: • int kill(pid_t pid, int sig) • To every process in group abs(gid): • int kill(pid_t gid, int sig), where gid is negative • Can we use signals to count events? • No • Why? Signals not queued!!

  6. Process 1 blocked pending kill(pid, SIGINT) other events Signals: sending Process 2 1 OS signal manager • divide by zero: SIGFPE • ctrl-c: SIGINT • child process exit: SIGCHLD OS Kernel

  7. blocked pending Signals: receiving Process 2 OS delivers the pending non-blocked signals 0 1 OS signal manager OS Kernel

  8. Key signals in the shell lab • SIGINT • Triggered by: Interrupt signal (ctrl-c) • Default action: the process terminates • SIGTSTP • Triggered by: Stop signal from terminal (ctrl-z) • Default action: the process stops • Can be restarted later(by sending SIGCONT to it) • SIGCHLD • Triggered by: a child process has stopped or terminated

  9. Shell: the process tree Shell pid=10 pgid=10 Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Backgroud process group 40 Child Child pid=21 pgid=20 pid=22 pgid=20 Each job has a unique process group id int setpgid(pid_t pid, pid_t pgid); setpgid(0, 0); Foreground process group 20

  10. Process tree for tsh UNIX shell pid=5 pgid=5 Foreground job receives SIGINT, SIGTSTP, when you type ctrl-c, ctrl-z pid=10 pgid=10 tsh Forward signals Fore- ground job Back- ground job #1 Back- ground job #2 pid=20 pgid=20 pid=32 pgid=32 pid=40 pgid=40 Background process group 32 Backgroud process group 40 Child Child int kill(pid_t pid, int sig) pid > 0: send sig to process with PID=pid pid = 0: send sig to all processes in my group pid = -1: send sig to all processes with PID>1 pid < -1: send sig to group abs(pid) pid=21 pgid=20 pid=22 pgid=20 Foreground process group 20

  11. Execute program int execve(const char *fname, char *const argv[], char *const envp[]); Examples: execve(“/bin/ls”, NULL, NULL); execve(“./mytest”, argv, envp); • What happens to the caller process? • It effectively terminates • The new program overwrites its state and takes its PID • Any signal handlers installed by the caller are reset

  12. Reaping terminated child processes pid_t waitpid(pid_t pid, int *status, int options) pid>0: wait for process with PID=pid -1: wait for any process pid<-1: wait for any process from group abs(pid) By default, waitpid blocks until at least one zombie process becomes available. options: WNOHANG: return immediately if no zombies available WUNTRACED: also return if some process has been stopped WNOHANG|WUNTRACED combination is very useful in the shell lab:it detects all the necessary events, and doesn’t block if no ‘’events’’

  13. Reaping terminated child processes pid_t waitpid(pid_t pid, int *status, int options) pid>0: wait for process with PID=pid -1: wait for any process pid<-1: wait for any process from group abs(pid) Return value: • pid of the process that exited, • or zero if WNOHANG was used and no zombie process available, • or -1 on error (then see errno) status: gives info on why the process terminated (or stopped if WUNTRACED used)

  14. Status • int status; waitpid(pid, &status, WNOHANG|WUNTRACED) Macros to evaluate status: • WIFEXITED(status):process exited normally • WEXITSTATUS(status):exit code of the process • WIFSIGNALED(status): process exited because a signal was not caught (SIGINT, SIGKILL, etc.) • WTERMSIG(status): identifies the signal that was not caught • WIFSTOPPED(status): process was stopped • WSTOPSIG(status): identifies the stopping signal

  15. Reaping child process in tsh • Where to put waitpid(…) ? • As the handout suggests:One centralized reaping for both fg and bg: • In sigchld_handler()

  16. Busy wait for foreground job tsh should still wait for fg job to complete, how? At an appropriate place in eval(): while(fg process still alive){ /* do nothing */ }

  17. Better than simple busy-waiting: Sleep At an appropriate place in eval(): while(fg process still alive){ sleep(1); }

  18. Race hazards • A data structure is shared by two pieces of code that can run concurrently • Different behaviors of program depending upon how the schedule interleaves the execution of code.

  19. An example of a race hazard sigchld_handler() { … waitpid(…)) … { deletejob(pid); } } eval() { pid = fork(); if(pid == 0) { /* child */ execve(…); } /* parent */ /* signal handler may run BEFORE addjob()*/ addjob(…); }

  20. Solution: blocking signals 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, …) }

  21. I/O Redirection • Covered in Chapter 11 Make file descriptor ‘newfd’ a copy of ‘oldfd’: dup2(int oldfd, int newfd); Get input from my_infd instead of standard input dup2(my_infd, STDIN_FILENO); Make a copy of a file descriptor (standard output in this case): int my_outfd = dup(STDOUT_FILENO);

  22. 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 • Flush output buffers: fflush(stdout); • STEP by STEP • Test your shell by typing commands first • Start now!

  23. What are the possible program outputs? #include <unistd.h> #include <stdio.h> int cnt = 0; int main(void) { if (fork() == 0){ cnt ++; // in child fork(); cnt++; } cnt ++; printf("%d", cnt); return 0; } Possible outputs: 133 313 331

More Related