1 / 18

L5: Writing Your Own Unix Shell October 1 6 , 2006

L5: Writing Your Own Unix Shell October 1 6 , 2006. 15-213 “The course that gives CMU its Zip!”. Topics L5: Shell Lab Processes Signals Reminders Shell Lab Due Oct 25, 2006 (wed). Section A (Donnie Kim) recitation6 .ppt (some slides courtesy of Kun Gao(S05) and Minglong Shao(F04).

helene
Télécharger la présentation

L5: Writing Your Own Unix Shell October 1 6 , 2006

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. L5: Writing Your Own Unix Shell October 16, 2006 15-213“The course that gives CMU its Zip!” • Topics • L5: Shell Lab • Processes • Signals • Reminders • Shell Lab Due Oct 25, 2006 (wed) Section A (Donnie Kim) recitation6.ppt (some slides courtesy of Kun Gao(S05) and Minglong Shao(F04)

  2. L5: Tiny Shell (tsh) • Things to learn from this lab: • Process Control (Ch 8) • Process ID (PID) and Process Group ID • Parent and Child process • Loading and running program • fork(), execve(), waitpid() • Signals (Ch 8) • Sending and receiving signals • Pending signal • Blocking/unblocking signal (avoiding race hazards) • I/O redirection (Ch 11) • dup2()

  3. Related Background Review (& Preview)

  4. Process Control • Process ID, Process Group ID and Parent Process ID • Each process has its own, unique process ID • pid_t getpid(void); // returns my pid • Every process belong to exactly one process group • pid_t getpgrp(void); // returns my prg id • Process creates process (parent – child) • pid_t getppid(void); // returns my parent’s pid [dhjkim@bluefish tshlab-handout]$ ps -jf UID PID PPID PGID SID C STIME TTY TIME CMD dhjkim 5469 5465 5469 5469 0 00:17 pts/7 00:00:00 -tcsh dhjkim 6284 5469 6284 5469 99 00:54 pts/7 02:58:42 ./test dhjkim 10139 5469 10139 5469 0 03:53 pts/7 00:00:00 ps -jf

  5. fork: Creating New Processes • int fork(void) • creates a new process (child process) that is identical to the calling process (parent process) • returns 0 to the child process • returns child’s pid to the parent process if (fork() == 0) { printf("hello from child\n"); } else { printf("hello from parent\n"); } Fork is interesting (and often confusing) because it is called once but returns twice • Any Scheduling order is Possible! • First parent then child or first child then parent can be executed depending on how OS scheduler decides

  6. exec: Loading and Running Programs • int execve(char *fname, char *argv[], char *envp[]) • New Program (*fname) overwrites its state and takes over the process’ PID main() { if (fork() == 0) { execve("/usr/bin/ls", NULL, NULL); } wait(NULL); exit(); }

  7. waitpid(): Waiting for a Specific Process • waitpid(pid, &status, options) • Can wait for specific process, and reap terminated child process • Various 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’’

  8. Signals • 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) // gid < 0 • pid_t getpid(void); // returns my pid • How to receive signals • Signal handler • handler_t *signal (int signum, handler_t *handler) • How to block and unblock signals • Explicitly Blocking Signals • int sigprocmask(int how, …, sigset_t *oldset)

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

  10. blocked pending Signals : How it actually works Process 2 Process 2 first checks pending/blocked vector when it gets scheduled 0 1 OS signal manager OS Kernel

  11. L5: Shell Lab

  12. Your task • eval() : Main routine that parses and interprets the command line • [300 lines, including helper functions] • sigchld_handler: Catches SIGCHILD signals [15 lines] • sigint_handler: Catches SIGINT(ctrl-c) signals [15 lines] • sigint_handler: Catches SIGSTP(ctrl-z) signals [15 lines]

  13. Overview • eval() : 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 should have a unique process group id int setpgid(pid_t pid, pid_t pgid); setpgid(0, 0); Foreground process group 20

  14. Overview UNIX shell pid=5 pgid=5 • eval() : 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

  15. Reaping Child Process • When fg or bg job is finished (child process terminated) shell (parent proces) has to reap the child, otherwise? • Foreground job: • We can wait • Background job: • Can we wait? • Where should waitpid() go?

  16. Race Hazards • sigchld_handler() { • … waitpid(…)) … { • deletejob(pid); • } • } • eval() { • pid = fork(); • if(pid == 0) • { /* child */ • execve(…); • } • /* parent */ • /* signal handler may run BEFORE addjob()*/ • addjob(…); • }

  17. Race Hazards (Solution?) • 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, …) • }

  18. Pop Quiz #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; }

More Related