Date post: | 17-Dec-2015 |
Category: |
Documents |
Upload: | lillian-clementine-tyler |
View: | 221 times |
Download: | 0 times |
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
OS Kernel
blockedpending1
Process 1 Process 2
other events
OS signal manager
kill(pid, SIGINT)
• divide by zero: SIGFPE
• ctrl-c: SIGINT
• child process exit: SIGCHLD
7
Signals: receiving
OS Kernel
blockedpending
Process 2
OS signal manager
0
OS delivers the pending non-blocked signals
1
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
Fore-ground
job
Back-groundjob #1
Back-groundjob #2
Shell
Child Child
pid=10pgid=10
Foregroundprocess group 20
Backgroundprocess group 32
Backgroudprocess group 40
pid=20pgid=20
pid=32pgid=32
pid=40pgid=40
pid=21pgid=20
pid=22pgid=20
Each job has a unique process group idint setpgid(pid_t pid, pid_t pgid);setpgid(0, 0);
10
Process tree for tsh
Fore-ground
job
Back-groundjob #1
Back-groundjob #2
tsh
Child Child
pid=10pgid=10
Foregroundprocess group 20
Backgroundprocess group 32
Backgroudprocess group 40
pid=20pgid=20
pid=32pgid=32
pid=40pgid=40
pid=21pgid=20
pid=22pgid=20
UNIXshell
pid=5pgid=5
Foreground jobreceives SIGINT, SIGTSTP, when you type ctrl-c, ctrl-z
Forward signals
int kill(pid_t pid, int sig)pid > 0: send sig to process with PID=pidpid = 0: send sig to all processes in my grouppid = -1: send sig to all processes with PID>1pid < -1: send sig to group abs(pid)
11
Execute programint 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 processespid_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 availableWUNTRACED: 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 processespid_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!