CS 105
Tour of the Black Holes of Computing!
Processes
Topics
cs105
Process context switches
Creating and destroying processes
Processes
Def: A process is an instance of a running program.
One of the most profound ideas in computer science.
Not the same as program or processor
Process provides each program with two key
abstractions:
Logical control flow
Each program seems to have exclusive use of the CPU.
Private address space
Each program seems to have exclusive use of main memory.
How are these illusions maintained?
Process executions interleaved (multitasking)
Address spaces managed by virtual memory system
CS 105
Logical Control Flows
Each process has its own logical control flow
Process A
Process B
Process C
Time
CS 105
Concurrent Processes
Two processes run concurrently (are concurrent) if their
flows overlap in time.
Otherwise, they are sequential.
Examples:
Concurrent: A & B, A & C
Sequential: B & C
Process A
Process B
Process C
Time
CS 105
User View: Concurrent Processes
Control flows for concurrent processes are physically
disjoint in time. (Except on multi-CPU machines.)
However, we can think of concurrent processes as
running in parallel with each other.
Process A
Process B
Process C
Time
CS 105
Context Switching
Processes are managed by a shared chunk of OS code
called the kernel
Important: the kernel is not a separate process, but rather
runs as part of (or on behalf of) some user process
Control flow passes from one process to another via a
context switch
Process A
code
Process B
code
user code
Time
kernel code
context switch
user code
kernel code
context switch
user code
6
CS 105
Private Address Spaces
Each process has its own private address space.
0xffffffff
0xc0000000
0x40000000
kernel virtual memory
(code, data, heap, stack)
user stack
(created at runtime)
read/write segment
(.data, .bss)
%esp (stack pointer)
memory mapped region for
shared libraries
run-time heap
(managed by malloc)
0x08048000
memory
invisible to
user code
read-only segment
(.init, .text, .rodata)
unused
brk
loaded from the
executable file
CS 105
fork: Creating New Processes
int fork(void)
Creates a new process (child process) that is identical to the
calling process (parent process)
Returns 0 to the child process
Returns childs pid to the parent process
if (fork() == 0) {
printf("hello from child\n");
} else {
printf("hello from parent\n");
}
Fork is interesting
(and often confusing)
because it is called
once but returns twice
Huh? Run that
by me again!
CS 105
Fork Example #1
Key Points
Parent and child both run same code
Distinguish parent from child by return value from fork
Start with same state, but each has private copy
Including shared input and output file descriptors
Relative ordering of their print statements undefined
void fork1()
{
int x = 1; // Parent and child will get private copies!
pid_t pid = fork();
if (pid == 0) {
printf("Child has x = %d\n", ++x);
} else {
printf("Parent has x = %d\n", --x);
}
printf("Bye from process %d with x = %d\n", getpid(), x);
}
9
CS 105
Fork Example #2
Key Points
Both parent and child can continue forking
void fork2()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("Bye\n");
}
10
L0
L1
Bye
Bye
L1
Bye
Bye
CS 105
Fork Example #3
Key Points
Both parent and child can continue forking
void fork3()
{
printf("L0\n");
fork();
printf("L1\n");
fork();
printf("L2\n");
fork();
printf("Bye\n");
}
L1
L0
11
L1
L2
Bye
Bye
L2
Bye
Bye
L2
Bye
Bye
L2
Bye
Bye
CS 105
Fork Example #4
Key Points
Both parent and child can continue forking
void fork4()
{
printf("L0\n");
if (fork() != 0) {
printf("L1\n");
if (fork() != 0) {
printf("L2\n");
fork();
}
}
printf("Bye\n");
}
12
Bye
Bye
L0
L1
L2
Bye
Bye
CS 105
Fork Example #5
Key Points
Both parent and child can continue forking
void fork5()
{
printf("L0\n");
if (fork() == 0) {
printf("L1\n");
if (fork() == 0) {
printf("L2\n");
fork();
}
}
printf("Bye\n");
}
13
Bye
L2
L1
L0
Bye
Bye
Bye
CS 105
exit: Destroying Process
void exit(int status)
Exits a process
Normally return with status 0 (success)
atexit() registers functions to be executed upon exit
void cleanup(void) {
printf("cleaning up\n");
}
void fork6() {
atexit(cleanup);
fork();
exit(0);
}
14
CS 105
Zombies
Idea
When process terminates, still consumes system resources
Various tables maintained by OS (to store exit status)
Called a zombie
Living corpse, half alive and half dead
Reaping
Performed by parent on terminated child
Parent is given exit status information
Kernel discards process
What If Parent Doesnt Reap?
15
If any parent terminates without reaping a child, then child
will be reaped by init process
Only need explicit reaping for long-running processes
E.g., shells and servers
CS 105
Zombie Example
void fork7()
{
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 */
}
}
linux> ./forks 7 &
[1] 6639
Running Parent, PID = 6639
Terminating Child, PID = 6640
linux> ps
PID TTY
TIME CMD
6585 ttyp9
00:00:00 tcsh
6639 ttyp9
00:00:03 forks
6640 ttyp9
00:00:00 forks <defunct>
6641 ttyp9
00:00:00 ps
linux> kill 6639
[1]
Terminated
linux> ps
PID TTY
TIME CMD
6585 ttyp9
00:00:00 tcsh
6642 ttyp9
00:00:00 ps
16
ps shows child
process as defunct
Killing parent allows
child to be reaped
CS 105
Nonterminating
Child
Example
void fork8()
{
if (fork() == 0) {
/* Child */
printf("Running Child, PID = %d\n",
getpid());
while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %d\n",
getpid());
linux> ./forks 8
exit(0);
Terminating Parent, PID = 6675
}
}
Running Child, PID = 6676
linux> ps
PID TTY
TIME
6585 ttyp9
00:00:00
6676 ttyp9
00:00:06
6677 ttyp9
00:00:00
linux> kill 6676
linux> ps
PID TTY
TIME
6585 ttyp9
00:00:00
6678 ttyp9
00:00:00
17
CMD
tcsh
forks
ps
CMD
tcsh
ps
Child process still active
even though parent has
terminated
Must kill explicitly, or else
will keep running
indefinitely
CS 105
wait: Synchronizing With Children
int wait(int *child_status)
18
Suspends current process until one of its children
terminates
Return value is pid of child process that terminated
If child_status != NULL, then integer it points to will be
set to indicate why child terminated
CS 105
wait: Synchronizing With
Children
void fork9() {
int child_status;
if (fork() == 0) {
printf("HC: hello from child\n");
}
else {
printf("HP: hello from parent\n");
wait(&child_status);
printf("CT: child has terminated\n");
}
printf("Bye\n");
exit(0);
}
19
HC Bye
HP
CT Bye
CS 105
Wait Example
If multiple children completed, will take in arbitrary order
Can use macros WIFEXITED and WEXITSTATUS to get
information about exit status
void fork10()
{
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0)
exit(100+i); /* Child */
for (i = 0; i < N; i++) {
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status
%d\n",
wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
20 }
CS 105
}
Waitpid
waitpid(pid, &status, options)
Can wait for specific process
Various options available (see man page)
void fork11()
{
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++)
if ((pid[i] = fork()) == 0)
exit(100+i); /* Child */
for (i = 0; i < N; i++) {
pid_t wpid = waitpid(pid[i], &child_status, 0);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n",
wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
}
21
CS 105
Wait/Waitpid Example Outputs
Using wait (fork10)
Child
Child
Child
Child
Child
3565
3564
3563
3562
3566
terminated
terminated
terminated
terminated
terminated
with
with
with
with
with
exit
exit
exit
exit
exit
status
status
status
status
status
103
102
101
100
104
Using waitpid (fork11)
Child
Child
Child
Child
Child
22
3568
3569
3570
3571
3572
terminated
terminated
terminated
terminated
terminated
with
with
with
with
with
exit
exit
exit
exit
exit
status
status
status
status
status
100
101
102
103
104
CS 105
exec: Running New Programs
int execl(char *path, char *arg0, char *arg1, , 0)
Loads and runs executable at path with args arg0, arg1,
path is the complete path of an executable
arg0 becomes the name of the process
Typically arg0 is either identical to path, or else it contains only the
executable filename from path
Real arguments to the executable start with arg1, etc.
List of args is terminated by a (char *)0 argument
Returns -1 if error, otherwise doesnt return!
main() {
if (fork() == 0) {
execl("/usr/bin/cp", "cp", "foo", "bar", NULL);
}
wait(NULL);
printf("copy completed\n");
exit(0);
}
23
CS 105
Summarizing
Processes
At any given time, system has multiple active processes
But only one (per CPU core) can execute at a time
Each process appears to have total control of processor +
private memory space
24
CS 105
Summarizing (cont.)
Spawning Processes
Call to fork
One call, two returns
Terminating Processes
Call exit
One call, no return
Reaping Processes
Call wait or waitpid
Replacing Program Executed by Process
Call execl (or variant)
One call, (normally) no return
25
CS 105