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

15-213, Fall 06

Jan 13, 2016

Download

Documents

odin

Outline Shell Lab Processes Signals. 15-213, Fall 06. 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 - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 15-213, Fall 06

1

15-213, Fall 06

Outline Shell Lab Processes Signals

Page 2: 15-213, Fall 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);

Page 3: 15-213, Fall 06

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

Page 4: 15-213, Fall 06

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

Page 5: 15-213, Fall 06

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!!

Page 6: 15-213, Fall 06

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

Page 7: 15-213, Fall 06

7

Signals: receiving

OS Kernel

blockedpending

Process 2

OS signal manager

0

OS delivers the pending non-blocked signals

1

Page 8: 15-213, Fall 06

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

Page 9: 15-213, Fall 06

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);

Page 10: 15-213, Fall 06

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)

Page 11: 15-213, Fall 06

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

Page 12: 15-213, Fall 06

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’’

Page 13: 15-213, Fall 06

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)

Page 14: 15-213, Fall 06

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

Page 15: 15-213, Fall 06

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()

Page 16: 15-213, Fall 06

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 */

}

Page 17: 15-213, Fall 06

17

Better than simple busy-waiting: Sleep

At an appropriate place in eval():

while(fg process still alive){

sleep(1);

}

Page 18: 15-213, Fall 06

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.

Page 19: 15-213, Fall 06

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(…);}

Page 20: 15-213, Fall 06

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, …)}

Page 21: 15-213, Fall 06

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);

Page 22: 15-213, Fall 06

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!

Page 23: 15-213, Fall 06

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