Lecture18
Lecture18
Announcements
•Assignment 3 grades out.
•Contact Mengqi Zhang if you have any questions.
2
Carnegie Mellon
Context Switching
• Processes are managed by a shared chunk of memory-resident
OS code called the kernel
• Important: the kernel is not a separate process, but rather runs as part of
some existing process.
user code
user code
3
Carnegie Mellon
Creating Processes
• Parent process creates a new child process by calling fork
• Child get an identical (but separate) copy of the parent’s (virtual)
address space (i.e., same stack copies, code, etc.)
•int fork(void)
• Returns 0 to the child process
• Returns child’s PID to the parent process
4
Carnegie Mellon
fork Example
int main() • Call once, return twice
{
pid_t pid;
• Concurrent execution
int x = 1; • Can’t predict execution
order of parent and child
pid = Fork();
if (pid == 0) { /* Child */ • Duplicate but separate
printf("child : x=%d\n", ++x); address space
exit(0); • x has a value of 1 when fork
}
returns in parent and child
/* Parent */ • Subsequent changes to x
printf("parent: x=%d\n", --x);
are independent
exit(0);
} fork.c • Shared open files
• stdout is the same in both
linux> ./fork parent and child
parent: x=0
child : x=2
5
Carnegie Mellon
brk
Run-time heap
(created by malloc)
Code Segment
int main()
{
pid_t pid;
int x = 1;
pid = Fork();
if (pid == 0) {
/* Child */
x++; // 2
exit(0);
}
/* Parent */
x--; // 0
exit(0);
}
7
Carnegie Mellon
Stack
x=1
Code Segment
int main()
{
pid_t pid;
int x = 1;
pid = Fork();
if (pid == 0) {
/* Child */
x++; // 2
exit(0);
}
/* Parent */
x--; // 0
exit(0);
}
7
Carnegie Mellon
Stack
x=1
Code Segment
int main()
{
pid_t pid;
Parent int x = 1;
Process
Program pid = Fork();
Counter if (pid == 0) {
/* Child */
x++; // 2
exit(0);
}
/* Parent */
x--; // 0
exit(0);
}
7
Carnegie Mellon
Stack Stack
x=1 x=1
/* Parent */ /* Parent */
x--; // 0 x--; // 0
exit(0); exit(0);
} }
7
Carnegie Mellon
Stack Stack
x=1 x=1
/* Parent */ /* Parent */
x--; // 0 x--; // 0
exit(0); exit(0);
} }
7
Carnegie Mellon
/* Parent */
printf("parent: x=%d\n", --x);
exit(0);
} fork.c
8
Carnegie Mellon
• Abstracted graph:
e f
a b c d
9
Carnegie Mellon
a b e c f d
a b c d
9
Carnegie Mellon
a b e c f d
a b c d
a b f c e d
9
Carnegie Mellon
void fork2()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("Bye\n");
} forks.c
10
Carnegie Mellon
10
Carnegie Mellon
Feasible output:
L0
L1
Bye
Bye
L1
Bye
Bye
10
Carnegie Mellon
11
Carnegie Mellon
11
Carnegie Mellon
11
Carnegie Mellon
11
Carnegie Mellon
12
Carnegie Mellon
12
Carnegie Mellon
12
Carnegie Mellon
12
Carnegie Mellon
• Reaping
• Performed by parent on terminated child (using wait or waitpid)
13
Carnegie Mellon
• Reaping
• Performed by parent on terminated child (using wait or waitpid)
• Parent is given exit status information
• Kernel then deletes zombie child process
13
Carnegie Mellon
void fork7() {
Zombie Example
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n", getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n", getpid());
while (1)
; /* Infinite loop */
}
} forks.c
14
Carnegie Mellon
void fork7() {
Zombie Example
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n", getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n", getpid());
while (1)
; /* Infinite loop */
}
} forks.c
void fork7() {
Zombie Example
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n", getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n", getpid());
while (1)
; /* Infinite loop */
}
} forks.c
void fork7() {
Zombie Example
if (fork() == 0) {
/* Child */
printf("Terminating Child, PID = %d\n", getpid());
exit(0);
} else {
printf("Running Parent, PID = %d\n", getpid());
while (1)
; /* Infinite loop */
}
} forks.c
15
Carnegie Mellon
void fork8()
{
if (fork() == 0) {
Non-terminating Child
/* Child */
printf("Running Child, PID = %d\n",
getpid());
while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %d\n",
getpid());
exit(0);
}
} forks.c
linux> ./forks 8
Terminating Parent, PID = 6675
Running Child, PID = 6676
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6676 ttyp9 00:00:06 forks
6677 ttyp9 00:00:00 ps
linux> kill 6676
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6678 ttyp9 00:00:00 ps
15
Carnegie Mellon
void fork8()
{
if (fork() == 0) {
Non-terminating Child
/* Child */
printf("Running Child, PID = %d\n",
getpid());
while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %d\n",
getpid());
exit(0);
}
} forks.c
linux> ./forks 8
Terminating Parent, PID = 6675
Running Child, PID = 6676
• Child process still active even
though parent has terminated.
linux> ps
PID TTY TIME CMD Can’t be reaped since it’s still
6585 ttyp9 00:00:00 tcsh running!
6676 ttyp9 00:00:06 forks
6677 ttyp9 00:00:00 ps • Must kill child explicitly, or else
linux> kill 6676 will keep running indefinitely
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6678 ttyp9 00:00:00 ps
15
Carnegie Mellon
if (fork() == 0) {
printf("HC: hello from child\n");
exit(0);
} else {
printf("HP: hello from parent\n");
wait(&child_status);
printf("CT: child has terminated\n");
}
printf("Bye\n");
} forks.c
16
Carnegie Mellon
16
Carnegie Mellon
Feasible output:
HC
HP
CT
Bye
16
Carnegie Mellon
17
Carnegie Mellon
20
Carnegie Mellon
21
Carnegie Mellon
21
Carnegie Mellon
21
Carnegie Mellon
21
Carnegie Mellon
Summary
• Processes
• At any given time, system has multiple active processes
• Only one can execute at a time on a single core, though
• Each process appears to have total control of processor + private memory space
• Spawning processes
• Call fork
• One call, two returns
• Process completion
• Call exit
• One call, no return
• Reaping and waiting for processes
• Call wait or waitpid
• Loading and running programs
• Call execve (or variant)
• One call, (normally) no return
22
Carnegie Mellon
Today
• Process Control
• Signals: The Way to Communicate with Processes
23
Carnegie Mellon
Signals
• A signal is a small message that notifies a process that an
event of some type has occurred in the system
• Sent from the OS kernel
• Could be requested by another process, by user, or automatically by
the kernel
• Signal type is identified by small integer ID’s (1-30)
24
Carnegie Mellon
Signals
• A signal is a small message that notifies a process that an
event of some type has occurred in the system
• Sent from the OS kernel
• Could be requested by another process, by user, or automatically by
the kernel
• Signal type is identified by small integer ID’s (1-30)
24
Carnegie Mellon
25
Carnegie Mellon
25
Carnegie Mellon
25
Carnegie Mellon
26
Carnegie Mellon
26
Carnegie Mellon
26
Carnegie Mellon
27
Carnegie Mellon
27
Carnegie Mellon
28
Carnegie Mellon
29
Carnegie Mellon
31
Carnegie Mellon
32
Carnegie Mellon
32
Carnegie Mellon
32
Carnegie Mellon
32
Carnegie Mellon
int main()
{
/* Install the SIGINT handler */
if (signal(SIGINT, sigint_handler) == SIG_ERR)
unix_error("signal error");
return 0;
} sigint.c
33