Recitation 7 (Oct. 25) Outline  Exceptions  Process  Signals  Non-local jumps Reminders  Lab4:  Due Thursday Minglong Shao [email protected] Office hours: Thursdays 5-6PM Wean Hall 1315

Download Report

Transcript Recitation 7 (Oct. 25) Outline  Exceptions  Process  Signals  Non-local jumps Reminders  Lab4:  Due Thursday Minglong Shao [email protected] Office hours: Thursdays 5-6PM Wean Hall 1315

Recitation 7 (Oct. 25)
Outline
 Exceptions
 Process
 Signals
 Non-local jumps
Reminders
 Lab4:
 Due Thursday
Minglong Shao
[email protected]
Office hours:
Thursdays 5-6PM
Wean Hall 1315
Exceptional control flow (ECF)
 Abrupt changes in the control flow

React to changes in system state that are not
captured by internal program variables and are
not necessarily related to the execution of the
program
 Happens at all levels of a computer system




Exceptions
Concurrent processes
Signals
Non-local jumps
Exceptions
 Interrupt (asynchronous exceptions)

I/O interrupt, hardware reset, software reset, etc.
 Traps

System calls, breakpoint traps, etc.
 Faults

Page fault, protection fault, etc.
 Aborts

Parity error, machine check, etc.
Process concept
 An instance of running program
 Multiple processes run “concurrently” by time
slicing

Context switching


Control flow passes from one process to another
Preemptive scheduler of OS
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
 A process can make a process group for itself and its
children



pid_t pid = getpid();
setpgid(0, 0);
getpgrp()
Create a new process
 int fork(void)

Create a new process that is identical to the
parent process
Return 0 to child process
Return child’s pid to the parent process

Call once, return twice


 Test your understanding…

Problem 1
Problem 1
#include <unistd.h>
#include <stdio.h>
int cnt = 0;
int main(void)
{
if (fork() == 0){
cnt ++;
fork();
cnt++;
}
cnt ++;
printf("%d", cnt);
return 0;
}
Possible output:
133
313
331
Reaping child process
 Child process becomes zombie when terminates


Still consume system resources
Parent performs reaping on terminated child
pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int
options)
 Straightforward for reaping a single child
 Tricky for Shell implementation!


Multiple child processes
Both foreground and background
 Practice time again: problem 2
Problem 2
int main(){
int status;
int counter = 1;
if (fork() == 0){
counter ++;
printf("%d", counter);
}else {
if (fork() == 0){
printf("9");
counter --;
printf("%d", counter);
exit(0);
}else {
if (wait(&status) > 0){
printf("6");
}
}
}
printf("8");
exit(0);
}
Answers:
A. Y
B. N
C. Y
D. N
E. Y
Signals
 Section 8.5 in text

Read at least twice … really!
 A signal tells our program that some event has
occurred
 Can we use signals to count events?


No
Why? Signals not queued!!
Important signals (Fig 8.23)
 SIGINT

Interrupt signal from terminal (ctrl-c)
 SIGTSTP

Stop signal from terminal (ctrl-z)
 SIGCHLD

A child process has stopped or terminated
Signals: sending
Process 1
Process 2
kill(pid, SIGINT)
1
blocked
pending
OS procedure
• divide by zero:
SIGFPE
• ctrl-c: SIGINT
• child process exit:
SIGCHLD
other events
OS Kernel
Signals: receiving
Check when
schedule the
process to run
Process 2
0
1
blocked
pending
OS procedure
OS Kernel
Receiving a signal
 Default action



The process terminates [and dumps core]
The process stops until restarted by a SIGCONT
signal (ctrl-z)
The process ignore the signal
 Can modify (additional action)
“Handle the signal” -- install signal handler
void sigint_handler(int sig);
signal(SIGINT, sigint_handler);

 An example: problem 3
Problem 3
void handler(int sig){
static int beeps = 0;
printf("YO\n");
if (++beeps < 2)
alarm(1); /* next SIGALRM will be delivered in 1s */
else{
printf("MA\n");
kill(getpid(), SIGKILL);
}
}
int main(){
Signal(SIGALRM, handler);
alarm(1); /* next SIGALRM will be delivered in 1s */
while (1)
;
printf(" is Great!\n");
return 0;
}
1. Output:
YO
YO
MA
2. The program will terminate
Signals not queued
int counter = 0;
void handler(int sig)
{
counter++;
sleep(1);
return;
}
Output:
sent SIGUSR2
sent SIGUSR2
sent SIGUSR2
sent SIGUSR2
sent SIGUSR2
counter = 1
int main()
{
int i;
signal(SIGUSER2, handler);
if (fork() == 0){
for (i = 0; i < 5; i++){
kill(getppid(), SIGUSR2);
printf(“sent SIGUSR2 to parent\n”);
}
exit(0);
}
wait(NULL);
printf(“counter = %d\n”, counter);
exit(0);
}
to
to
to
to
to
parent
parent
parent
parent
parent
Race hazard
 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.
An example of race hazard
sigchld_handler() {
pid = waitpid(…);
deletejob(pid);
}
eval() {
pid = fork();
if(pid == 0)
{ /* child */
execve(…);
}
/* parent */
/* signal handler may run BEFORE addjob()*/
addjob(…);
}
An okay schedule
time
Shell
Signal Handler
Child
fork()
addjob()
execve()
exit()
sigchld_handler()
deletejobs()
A problematic schedule
time
Shell
Signal Handler
Child
fork()
execve()
exit()
sigchld_handler()
deletejobs()
addjob()
Job added to job list after the signal handler tried to delete it!
Solution: blocking signals
sigchld_handler() {
pid = waitpid(…);
deletejob(pid);
}
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, …)
}
More details 8.5.6 (page 633)
Non-local jump
int setjmp(jmp_buf env)
 Must called before longjmp
 Stores current register context, stack pointer, and PC in
the jump buffer env
 First called, return 0 if no error
void longjmp(jmp_buf env, int i)
 Restores register context from jump buffer env
 Jumps back to where previous setjmp is called, behaves
like setjmp just completes. But this time it returns i, not 0
Can only jump to an active context
 A function that has been called but not yet
completed
Non-local jump (cont)
int sigsetjmp(jmp_buf env)
 Also saves blocked signals
void siglongjmp(jmp_buf env, int i)
 Restores blocked signals besides others
Let’s see an example: problem 4
Problem 4
jmp_buf stuff;
jmp_buf more_stuff;
int bar(){
if (setjmp(more_stuff) == 0)
return 3;
else
return 6;
}
int foo(){
char c = getc(stdin);
if (c == 'x')
longjmp(stuff, 42);
else if (c == 'y')
longjmp(more_stuff, 17);
else
return bar();
return -1;
}
int main()
{
int n;
n = setjmp(stuff);
while ((n+=foo())<0)
sleep(1);
printf("%d\n", n);
}
Answer:
1. 3
2. 45
3. 45
4. ?
5. ?
Summary
 Process
 fork(), waitpid(), execl() (and variant)
 Reaping child processes
 Signals
 signal(), install handler, signals not queued
 Non-local jumps
 Check man page to understand the system calls
better

man waitpid (fork, signal, …)
 Read test book!