23
1 15-213, Fall 06 Outline Shell Lab Processes Signals

1 15-213, Fall 06 Outline Shell Lab Processes Signals

Embed Size (px)

Citation preview

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

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!

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:133313331