Download presentation
Published byLillian Clementine Tyler Modified over 9 years ago
1
15-213, Fall 06 Outline Shell Lab Processes Signals
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
Signals: sending other events OS Kernel blocked pending
Process 1 Process 2 blocked kill(pid, SIGINT) pending 1 OS signal manager other events divide by zero: SIGFPE ctrl-c: SIGINT child process exit: SIGCHLD OS Kernel
7
Signals: receiving OS delivers the pending non-blocked signals
Process 2 blocked pending 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
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 int kill(pid_t pid, int sig) Forward signals
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 What happens to the caller process?
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(…);
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
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.