0% found this document useful (0 votes)
13 views66 pages

18 Processes

Uploaded by

jjmushumbusi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views66 pages

18 Processes

Uploaded by

jjmushumbusi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 66

Carnegie Mellon

Processes and Multitasking


15-213/15-513: Introduction to Computer Systems
18th Lecture, June 25, 2024

Instructors:
Brian Railing

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 1


Carnegie Mellon

Today
 Processes
 System Calls
 Process Control
 Shells

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 2


Carnegie Mellon

Earliest days: One batch job at a time

IBM 704 at Langley Research Center (NASA), 1957


https://commons.wikimedia.org/w/index.php?curid=6455009
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 3
Carnegie Mellon

How can many people share one


computer efficiently?

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 4


Carnegie Mellon

Multiprocessing
Memory Memory Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code

CPU CPU CPU


Registers Registers Registers

 Computer runs many processes simultaneously


▪ Applications for one or more users
Web browsers, email clients, editors, …

▪ Background tasks
▪ Monitoring network & I/O devices

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 5


Carnegie Mellon

Multiprocessing Example

 Running program “top” on hammerheadshark


▪ System has 425 “tasks”, 7 of which are active
▪ Identified by Process ID (PID), user account, command name
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 6
Carnegie Mellon

Processes
 Definition: A process is an instance of a running Memory
program. Stack
▪ One of the most profound ideas in computer science Heap
▪ Not the same as “program” or “processor” Data
Code

 Process provides each program with two key CPU


abstractions: Registers
▪ Private address space
Each program seems to have exclusive use of main

memory.
▪ Provided by kernel mechanism called virtual memory
▪ Logical control flow
▪ Each program seems to have exclusive use of the CPU
▪ Provided by kernel mechanism called context switching

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 7


Carnegie Mellon

Control Flow
 Processors do only one thing:
▪ From startup to shutdown, each CPU core simply reads and executes
a sequence of machine instructions, one at a time *
▪ This sequence is the CPU’s control flow (or flow of control)

Physical control flow


<startup>
inst1
inst2
Time
inst3

instn * many modern CPUs execute
<shutdown> several instructions at once
and/or out of program order, but
this is invisible to the programmer
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 8
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.
 Control flow passes from one process to another via a
context switch
Process A Process B

user code

kernel code context switch


Time user code

kernel code context switch

user code

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 9


Carnegie Mellon

Context Switching (Uniprocessor)


Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code
Saved Saved
registers registers

CPU
Registers

 Single processor executes multiple processes concurrently


▪ Process executions interleaved (multitasking)
▪ Address spaces managed by virtual memory system (like last week)
▪ Register values for nonexecuting processes saved in memory
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 10
Carnegie Mellon

Context Switching (Uniprocessor)


Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code
Saved Saved Saved
registers registers registers

CPU
Registers

 Save current registers in memory

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 11


Carnegie Mellon

Context Switching (Uniprocessor)


Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code
Saved Saved Saved
registers registers registers

CPU
Registers

 Schedule next process for execution

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 12


Carnegie Mellon

Context Switching (Uniprocessor)


Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code
Saved Saved Saved
registers registers registers

CPU
Registers

 Load saved registers and switch address space (context switch)

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 13


Carnegie Mellon

Context Switching (Multicore)


Memory
Stack Stack Stack
Heap Heap Heap
Data Data … Data
Code Code Code
Saved
registers

CPU CPU  Multicore processors


Registers Registers ▪ Multiple CPUs on single chip
▪ Share main memory (and some caches)
▪ Each can execute a separate process
▪ Scheduling of processors onto cores
done by kernel

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 14


Carnegie Mellon

User View of Concurrent Processes


 Two processes run concurrently (are concurrent) if their
execution overlaps in time
 Otherwise, they are sequential
 Appears as if concurrent processes run in parallel with
each other
▪ This means they can interfere with each other
(more on that in a couple weeks)
A and B
concurrent
Process A Process B Process C
A and C
concurrent
Time
B and C
sequential

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 15


Carnegie Mellon

Traditional (Uniprocessor) Reality


 Only one process runs at a time
 A and B execution is interleaved, not truly concurrent
 Similarly for A and C
 Still possible for A and B / A and C to interfere with each
other

Process A Process B Process C

Time

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 16


Carnegie Mellon

How does the kernel take control?


 The CPU executes instructions in sequence
 We don’t write “now run kernel code” in our programs…
▪ Or do we??

Physical control flow


<startup>
<kernel entry>
inst1
insta
inst2
Time instb
inst
syscall
3
instc


instn
<kernel exit>
<shutdown>

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 17


Carnegie Mellon

Today
 Processes
 System Calls
 Process Control
 Shells

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 18


Carnegie Mellon

System Calls
 Whenever a program wants to
// fopen.c
cause an effect outside its own FILE *fopen(const char *fname,
const char *mode) {
process, it must ask the kernel int flags = mode2flags(mode);
for help if (!flags) return NULL;
int fd = open(fname, flags,
 Examples: DEFPERMS);
if (fd == -1) return NULL;
▪ Read/write files return fdopen(fd, mode);
}
▪ Get current time
// open.S
▪ Allocate RAM (sbrk) .global open
▪ Create new processes open:
mov $SYS_open, %eax
syscall
cmp $SYS_error_thresh, %rax
ja __syscall_error
ret

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 19


Carnegie Mellon

All the system calls


accept fanotify_init getresuid llistxattr nfsservctl recvmmsg set_mempolicy_home_node sync_file_range
accept4 fanotify_mark getrlimit lookup_dcookie open_by_handle_at recvmsg set_robust_list sync_file_range2
acct fchdir getrusage lremovexattr open_tree remap_file_pages set_tid_address syncfs
add_key fchmod getsid lsetxattr openat removexattr setdomainname sysinfo
adjtimex fchmodat getsockname madvise openat2 renameat setfsgid syslog
bind fchown getsockopt mbind perf_event_open renameat2 setfsuid tee
bpf fchownat gettid membarrier personality request_key setgid tgkill
brk fdatasync gettimeofday memfd_create pidfd_getfd restart_syscall setgroups timer_create
capget fgetxattr getuid memfd_secret pidfd_open rseq sethostname timer_delete
capset finit_module getxattr migrate_pages pidfd_send_signal rt_sigaction setitimer timer_getoverrun
chdir flistxattr init_module mincore pipe2 rt_sigpending setns timer_gettime
chroot flock inotify_add_watch mkdirat pivot_root rt_sigprocmask setpgid timer_settime
clock_adjtime fremovexattr inotify_init1 mknodat pkey_alloc rt_sigqueueinfo setpriority timerfd_create
clock_getres fsconfig inotify_rm_watch mlock pkey_free rt_sigreturn setregid timerfd_gettime
clock_gettime fsetxattr io_cancel mlock2 pkey_mprotect rt_sigsuspend setresgid timerfd_settime
clock_nanosleep fsmount io_destroy mlockall ppoll rt_sigtimedwait setresuid times
clock_settime fsopen io_getevents mount prctl rt_tgsigqueueinfo setreuid tkill
clone fspick io_pgetevents mount_setattr pread64 sched_get_priority_max setrlimit umask
clone3 fsync io_setup move_mount preadv sched_get_priority_min setsid umount2
close futex io_submit move_pages preadv2 sched_getaffinity setsockopt uname
close_range futex_waitv io_uring_enter mprotect prlimit64 sched_getattr settimeofday unlinkat
connect get_mempolicy io_uring_register mq_getsetattr process_madvise sched_getparam setuid unshare
copy_file_range get_robust_list io_uring_setup mq_notify process_mrelease sched_getscheduler setxattr userfaultfd
delete_module getcpu ioctl mq_open process_vm_readv sched_rr_get_interval shmat utimensat
dup getcwd ioprio_get mq_timedreceive process_vm_writev sched_setaffinity shmctl vhangup
dup3 getdents64 ioprio_set mq_timedsend pselect6 sched_setattr shmdt vmsplice
epoll_create1 getegid kcmp mq_unlink ptrace sched_setparam shmget wait4
epoll_ctl geteuid kexec_file_load mremap pwrite64 sched_setscheduler shutdown waitid
epoll_pwait getgid kexec_load msgctl pwritev sched_yield sigaltstack write
epoll_pwait2 getgroups keyctl msgget pwritev2 seccomp signalfd4 writev
eventfd2 getitimer kill msgrcv quotactl semctl socket
execve getpeername landlock_add_rule msgsnd quotactl_fd semget socketpair
execveat getpgid landlock_create_ruleset msync read semop splice
exit getpid landlock_restrict_self munlock readahead semtimedop statx
exit_group getppid lgetxattr munlockall readlinkat sendmmsg swapoff
faccessat getpriority linkat munmap readv sendmsg swapon
faccessat2 getrandom listen name_to_handle_at reboot sendto symlinkat
fallocate getresgid listxattr nanosleep recvfrom set_mempolicy sync

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 20


Carnegie Mellon

System Call Error Handling


 Almost all system-level operations can fail
▪ Only exception is the handful of functions that return void
▪ You must explicitly check for failure
 On error, most system-level functions return −1 and set
global variable errno to indicate cause.
 Example:

pid_t pid = fork();


if (pid == -1) {
fprintf(stderr, "fork error: %s\n", strerror(errno));
exit(1);
}

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 21


Carnegie Mellon

Error-reporting functions
 Can simplify somewhat using an error-reporting function:
void unix_error(char *msg) /* Unix-style error */
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(1);
}

pid_t pid = fork(); Note: csapp.c exits with 0.


if (pid == -1)
unix_error("fork error");

 Not always appropriate to exit when something goes


wrong.

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 22


Carnegie Mellon

Error-handling Wrappers
 We simplify the code we present to you even further by
using Stevens1-style error-handling wrappers:
pid_t Fork(void)
{
pid_t pid = fork();

if (pid == -1)
unix_error("Fork error");
return pid;
}

pid = Fork(); // Only returns if successful

 NOT what you generally want to do in a real application


1e.g., in “UNIX Network Programming: The sockets networking API“ W. Richard Stevens

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 23


Carnegie Mellon

Today
 Processes
 System Calls
 Process Control
 Shells

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 24


Carnegie Mellon

Obtaining Process IDs


 pid_t getpid(void)
▪ Returns PID of current process

 pid_t getppid(void)
▪ Returns PID of parent process

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 25


Carnegie Mellon

Process States
At any time, each process is either:
 Running
▪ Process is either executing instructions, or it could be executing
instructions if there were enough CPU cores.
 Blocked / Sleeping
▪ Process cannot execute any more instructions until some external
event happens (usually I/O).
 Stopped
▪ Process has been prevented from executing by user action
(control-Z).
 Terminated / Zombie
▪ Process is finished. Parent process has not yet been notified.

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 26


Carnegie Mellon

Terminating Processes
 Process becomes terminated for one of three reasons:
▪ Receiving a signal whose default action is to terminate (next lecture)
▪ Returning from the main routine
▪ Calling the exit function

 void exit(int status)


▪ Terminates with an exit status of status
▪ Convention: normal return status is 0, nonzero on error
▪ Another way to explicitly set the exit status is to return an integer value
from the main routine

 exit is called once but never returns.

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 27


Carnegie Mellon

Creating Processes
 Parent process creates a new running child process by
calling fork

 int fork(void)
▪ Returns 0 to the child process, child’s PID to parent process
▪ Child is almost identical to parent:
▪ Child get an identical (but separate) copy of the parent’s virtual
address space.
▪ Child gets identical copies of the parent’s open file descriptors
▪ Child has a different PID than the parent

 fork is interesting (and often confusing) because


it is called once but returns twice

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 28


Carnegie Mellon

Conceptual View of fork


Memory Memory
parent child
Stack Stack Stack
Heap ➔ Heap Heap
Data Data Data
Code Code Code
Saved Saved Saved
registers registers registers

CPU CPU
Registers Registers

 Make complete copy of execution state


▪ Designate one as parent and one as child
▪ Resume execution of parent or child
▪ (Optimization: Use copy-on-write to avoid copying RAM)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 29
Carnegie Mellon

fork Example
int main(int argc, char** argv)  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 */
printf("child : x=%d\n", ++x);
return 0;
}

/* Parent */
printf("parent: x=%d\n", --x);
return 0;
} fork.c

linux> ./fork linux> ./fork linux> ./fork linux> ./fork


parent: x=0 child : x=2 parent: x=0 parent: x=0
child : x=2 parent: x=0 child : x=2 child : x=2

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 30


Carnegie Mellon

fork Example  Call once, return twice


int main(int argc, char** argv)
{  Concurrent execution
pid_t pid; ▪ Can’t predict execution
int x = 1;
order of parent and child
pid = Fork();  Duplicate but separate
if (pid == 0) { /* Child */
printf("child : x=%d\n", ++x); address space
return 0; ▪ x has a value of 1 when
}
fork returns in parent and
/* Parent */ child
printf("parent: x=%d\n", --x); ▪ Subsequent changes to x
return 0;
}
are independent
 Shared open files
▪ stdout is the same in
linux> ./fork
parent: x=0 both parent and child
child : x=2

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 31


Carnegie Mellon

Modeling fork with Process Graphs


 A process graph is a useful tool for capturing the partial
ordering of statements in a concurrent program:
▪ Each vertex is the execution of a statement
▪ a -> b means a happens before b
▪ Edges can be labeled with current value of variables
▪ printf vertices can be labeled with output
▪ Each graph begins with a vertex with no inedges
 Any topological sort of the graph corresponds to a feasible
total ordering.
▪ Total ordering of vertices where all edges point from left to right

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 32


Carnegie Mellon

Process Graph Example


int main(int argc, char** argv)
{
pid_t pid;
int x = 1;
child: x=2
pid = Fork(); Child
printf exit
if (pid == 0) { /* Child */
printf("child : x=%d\n", ++x); x==1 parent: x=0
Parent
return 0; main fork printf exit
}

/* Parent */
printf("parent: x=%d\n", --x);
return 0;
} fork.c

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 33


Carnegie Mellon

Interpreting Process Graphs


 Original graph:
child: x=2
printf exit
x==1 parent: x=0
main for printf exit
k
Feasible total ordering:
 Relabled graph:
e f
a b e c f d

a b c d
Feasible or Infeasible?

a b f c e d
Infeasible: not a topological sort
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 34
Carnegie Mellon

fork Example: Two consecutive forks


Bye
void fork2() printf
{ L1 Bye
printf("L0\n"); printf fork printf
fork(); Bye
printf("L1\n"); printf
fork();
printf("Bye\n"); L0 L1 Bye
} forks.c printf fork printf fork printf

Feasible output: Infeasible output:


L0 L0
L1 Bye
Bye L1
Bye Bye
L1 L1
Bye Bye
Bye Bye
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 35
Carnegie Mellon

fork Example: Nested forks in parent


void fork4()
{
printf("L0\n"); Bye Bye
if (fork() != 0) { printf printf
printf("L1\n"); L0 L1 L2 Bye
if (fork() != 0) { printf fork printf fork printf printf
printf("L2\n");
}
}
printf("Bye\n");
} forks.c Feasible or Infeasible? Feasible or Infeasible?
L0 L0
Bye L1
L1 Bye
Bye Bye
Bye L2
L2 Bye
Infeasible Feasible
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 36
Carnegie Mellon

fork Example: Nested forks in children


void fork5()
{ L2 Bye
printf("L0\n"); printf printf
if (fork() == 0) { L1 Bye
printf("L1\n"); printf fork printf
if (fork() == 0) { L0 Bye
printf("L2\n"); printf fork printf
}
}
printf("Bye\n");
} forks.c Feasible or Infeasible? Feasible or Infeasible?
L0 L0
Bye Bye
L1 L1
Bye L2
Bye Bye
L2 Bye
Infeasible Feasible
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 37
Carnegie Mellon

Reaping Child Processes


 Idea
▪ When process terminates, it still consumes system resources
Examples: Exit status, various OS tables

▪ Called a “zombie”
▪ Living corpse, half alive and half dead

 Reaping
▪ Performed by parent on terminated child (using wait or waitpid)
▪ Parent is given exit status information
▪ Kernel then deletes zombie child process
 What if parent doesn’t reap?
▪ If any parent terminates without reaping a child, then the orphaned
child should be reaped by init process (pid == 1)
▪ Unless it was init that terminated! Then need to reboot…
▪ So, only need explicit reaping in long-running processes
▪ e.g., shells and servers
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 38
Carnegie Mellon

void fork7() {
Zombie if (fork() == 0) {
/* Child */

Example 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 } forks.c
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
 ps shows child process as
6640 ttyp9 00:00:00 forks <defunct> “defunct” (i.e., a zombie)
6641 ttyp9 00:00:00 ps
linux> kill 6639
[1] Terminated  Killing parent allows child to
linux> ps be reaped by init
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6642 ttyp9 00:00:00 ps

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 39


Carnegie Mellon

void fork8()
Non- {
if (fork() == 0) {
terminating /* Child */
printf("Running Child, PID = %d\n",

Child Example getpid());


while (1)
; /* Infinite loop */
} else {
printf("Terminating Parent, PID = %d\n",
getpid());
exit(0);
}
linux> ./forks 8
} forks.c
Terminating Parent, PID = 6675
Running Child, PID = 6676  Child process still active even
linux> ps though parent has terminated
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6676 ttyp9 00:00:06 forks  Must kill child explicitly, or else will
6677 ttyp9 00:00:00 ps
keep running indefinitely
linux> kill 6676
linux> ps
PID TTY TIME CMD
6585 ttyp9 00:00:00 tcsh
6678 ttyp9 00:00:00 ps
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 40
Carnegie Mellon

wait: Synchronizing with Children


 Parent reaps a child with one of these system calls:
 pid_t wait(int *status)
▪ Suspends current process until one of its children terminates
▪ Returns PID of child, records exit status in status

 pid_t waitpid(pid_t pid, int *status,


int options)
▪ More flexible version of wait:
▪ Can wait for a specific child or group of children
▪ Can be told to return immediately if there are no children to reap

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 41


Carnegie Mellon

wait: Synchronizing with Children


void fork9() {
int child_status;
HC exit
if (fork() == 0) { printf
printf("HC: hello from child\n");
exit(0);
CT
} else {
HP Bye
printf("HP: hello from parent\n");
wait(&child_status); fork printf wait printf
printf("CT: child has terminated\n");
}
printf("Bye\n");
} forks.c

Feasible output(s):
output: Infeasible output:
HC HP HP
HP HC CT
CT CT Bye
Bye Bye HC
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 42
Carnegie Mellon

wait: Status codes


 Return value of wait is the pid of the child process that
terminated
 If status != NULL, then the integer it points to will be
set to a value that indicates the exit status
▪ More information than the value passed to exit
▪ Must be decoded, using macros defined in sys/wait.h
▪ WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG,
WIFSTOPPED, WSTOPSIG, WIFCONTINUED
▪ See textbook for details

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 43


Carnegie Mellon

Another 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, child_status;

for (i = 0; i < N; i++)


if ((pid[i] = fork()) == 0) {
exit(100+i); /* Child */
}
for (i = 0; i < N; i++) { /* Parent */
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 terminate abnormally\n", wpid);
}
} forks.c
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 44
Carnegie Mellon

waitpid: Waiting for a Specific Process


 pid_t waitpid(pid_t pid, int *status, int options)
▪ Suspends current process until specific process terminates
▪ Various options (see textbook)
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 = N-1; i >= 0; 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 terminate abnormally\n", wpid);
}
} forks.c
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 45
Carnegie Mellon

execve: Loading and Running Programs


 int execve(char *filename, char *argv[], char *envp[])
 Loads and runs in the current process:
▪ Executable file filename
Can be object file or script file beginning with #!interpreter

(e.g., #!/bin/bash)
▪ …with argument list argv
▪ By convention argv[0]==filename
▪ …and environment variable list envp
▪ “name=value” strings (e.g., USER=droh)
▪ getenv, putenv, printenv

 Overwrites code, data, and stack


▪ Retains PID, open files and signal context
 Called once and never returns
▪ …except if there is an error
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 46
Carnegie Mellon

execve Example
 Execute "/bin/ls –lt /usr/include" in child process
using current environment:
envp[n] = NULL
envp[n-1] "PWD=/usr/droh"

envp[0] "USER=droh"
environ
myargv[argc] = NULL
(argc == 3) myargv[2] "/usr/include"
myargv[1] "-lt"
myargv myargv[0] "/bin/ls"

if ((pid = Fork()) == 0) { /* Child runs program */


if (execve(myargv[0], myargv, environ) < 0) {
printf("%s: %s\n", myargv[0], strerror(errno));
exit(1);
}
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 47
Carnegie Mellon

Null-terminated Bottom of stack

Structure of environment variable strings


Null-terminated
the stack when command-line arg strings

a new program envp[n] == NULL


starts envp[n-1]
...
environ
(global var)
envp[0]
argv[argc] = NULL envp
argv[argc-1] (in %rdx)
...
argv argv[0]
(in %rsi)

argc Stack frame for


(in %rdi) libc_start_main
Top of stack
Future stack frame for
main

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 48


Carnegie Mellon

execve and process memory layout


User stack Private, demand-zero  To load and run a new
program a.out in the
current process using
execve:
libc.so
.data Memory mapped region
Shared, file-backed
 Free vm_area_struct’s
.text for shared libraries and page tables for old areas

 Create vm_area_struct’s
and page tables for new
Runtime heap (via malloc) Private, demand-zero areas
▪ Programs and initialized data
Uninitialized data (.bss) Private, demand-zero backed by object files.
a.out ▪ .bss and stack backed by
.data Initialized data (.data) anonymous files.
Private, file-backed
.text Program text (.text)
 Set PC to entry point in
0 .text
▪ Linux will fault in code and
data pages as needed.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 49
Carnegie Mellon

Quiz

https://canvas.cmu.edu/courses/40739/quizzes/123420

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 50


Carnegie Mellon

Today
 Processes
 System Calls
 Process Control
 Shells

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 51


Carnegie Mellon

Shell Programs
 A shell is an application program that runs programs on behalf
of the user
▪ sh Original Unix shell (Stephen Bourne, AT&T Bell Labs, 1977)
▪ csh/tcsh BSD Unix C shell
▪ bash “Bourne-Again” Shell (default Linux shell)

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 52


Carnegie Mellon

Shell Programs
 Simple shell
▪ Described in the textbook, starting at p. 753
▪ Implementation of a very elementary shell
▪ Purpose
▪ Understand what happens when you type commands
▪ Understand use and operation of process control operations

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 53


Carnegie Mellon

Simple Shell Example


linux> ./shellex
> /bin/ls -l csapp.c Must give full pathnames for programs
-rw-r--r-- 1 bryant users 23053 Jun 15 2015 csapp.c
> /bin/ps
PID TTY TIME CMD
31542 pts/2 00:00:01 tcsh
32017 pts/2 00:00:00 shellex
32019 pts/2 00:00:00 ps
> /bin/sleep 10 & Run program in background
32031 /bin/sleep 10 &
> /bin/ps
PID TTY TIME CMD
31542 pts/2 00:00:01 tcsh
32024 pts/2 00:00:00 emacs
32030 pts/2 00:00:00 shellex
32031 pts/2 00:00:00 sleep Sleep is running
32033 pts/2 00:00:00 ps in background
> quit

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 54


Carnegie Mellon

Simple Shell Implementation


 Basic loop
▪ Read line from command line
▪ Execute the requested operation
▪ Built-in command (only one implemented is quit)
▪ Load and execute program from file

int main(int argc, char** argv)


{ Execution is a
char cmdline[MAXLINE]; /* command line */ sequence of
while (1) { read/evaluate
/* read */ steps
printf("> ");
fgets(cmdline, MAXLINE, stdin);
if (feof(stdin))
exit(0);

/* evaluate */
eval(cmdline);
}
... shellex.c
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 55
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
parseline will parse ‘buf’ into
if (!builtin_command(argv)) {
if ((pid = Fork()) == 0) { ‘argv’ and return whether or not
/* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
input line ended in ‘&’
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
}
return;
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 56
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */ Ignore empty lines.
if (!builtin_command(argv)) {
if ((pid = Fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
}
return;
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 57
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = Fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
} If it is a ‘built in’ command, then handle it
/*
if
here in
Parent waits for foreground
(!bg) {
this program.
job Otherwise
to terminate */
int status; fork/exec the program specified in argv[0]
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
}
return;
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 58
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
} Create child
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
}
return;
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 59
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
execve(argv[0], argv, environ);
// If we get here, execve failed.
printf("%s: %s\n", argv[0], strerror(errno));
exit(127);
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
Start argv[0].
}
printf("%d %s", pid, cmdline); execve only returns on error.
return;
}

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition


shellex.c 60
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
execve(argv[0], argv, environ);
// If we get here, execve failed.
printf("%s: %s\n", argv[0], strerror(errno));
exit(127);
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
If running child in
}
return;
foreground, wait until it is
} done.
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 61
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
execve(argv[0], argv, environ);
// If we get here, execve failed.
printf("%s: %s\n", argv[0], strerror(errno));
exit(127);
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
If running child in
}
unix_error("waitfg: waitpid error"); background, print pid
else
printf("%d %s\n", pid, cmdline);
and continue doing
}
return;
other stuff.
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 62
Carnegie Mellon

Simple Shell eval Function


void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = fork()) == 0) { /* Child runs user job */
execve(argv[0], argv, environ);
// If we get here, execve failed.
printf("%s: %s\n", argv[0], strerror(errno));
exit(127);
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error"); Oops. There is a
}
else
printf("%d %s", pid, cmdline);
problem with
}
return; this code.
}
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition
shellex.c 63
Carnegie Mellon

Problem with Simple Shell Example


 Shell designed to run indefinitely
▪ Should not accumulate unneeded resources
▪ Memory
▪ Child processes
▪ File descriptors
 Our example shell correctly waits for and reaps foreground
jobs

 But what about background jobs?


▪ Will become zombies when they terminate
▪ Will never be reaped because shell (typically) will not terminate
▪ Could run the entire computer out of memory
▪ More likely, run out of PIDs

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 64


Carnegie Mellon

Summary
 Processes
▪ At any given time, system has multiple active processes
▪ Only one can execute at a time on any single core
▪ Each process appears to have total control of
processor + private memory space

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 65


Carnegie Mellon

Summary (cont.)
 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

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 66

You might also like