0% found this document useful (0 votes)
42 views28 pages

3 Process Syscall

The document discusses system calls for process management in operating systems, focusing on APIs for creating, running, and terminating processes. It explains key system calls like fork(), exec(), exit(), and wait(), detailing their functions and interactions in Unix-like systems. Additionally, it covers concepts such as process groups, signals, and I/O redirection, emphasizing the importance of these mechanisms for efficient process management and communication.

Uploaded by

Vistas Flamingo
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)
42 views28 pages

3 Process Syscall

The document discusses system calls for process management in operating systems, focusing on APIs for creating, running, and terminating processes. It explains key system calls like fork(), exec(), exit(), and wait(), detailing their functions and interactions in Unix-like systems. Additionally, it covers concepts such as process groups, signals, and I/O redirection, emphasizing the importance of these mechanisms for efficient process management and communication.

Uploaded by

Vistas Flamingo
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/ 28

System calls for process management

Mythili Vutukuru
CSE, IIT Bombay
API for process management
• What API does OS provide to user programs to manage processes?
• How to create, run, terminate processes?
• API = Application Programming Interface
= functions available to write user programs
• API provided by OS is a set of “system calls”
• System call is a function call into OS code that runs at higher CPU privilege level
• Sensitive operations (e.g., access to hardware) are allowed only at a higher
privilege level
• Some “blocking” system calls cause the process to be blocked and
context switched out (e.g., read() from disk), while others (e.g., getpid()
to get PID) can return immediately
2
Portability of code across OS
• POSIX API: standard set of system calls (and some C library functions)
available to user programs, defined for portability
• Programs written using POSIX API can run on any POSIX compliant OS
• Most modern OSes are POSIX compliant
• Program may still need to be recompiled for different architectures
• Program language libraries hide the details of invoking system calls
• The printf function in libc calls the write system call to write to screen
• User programs usually do not need to worry about invoking system calls
• ABI (application binary interface) is the interface between machine
code and underlying hardware: ISA, calling convention, …
3
Process related system calls (in Unix)
• fork() creates a new child process
• All processes are created by forking from a parent
• OS starts init process after boot up, which forks other processes
• The init process is ancestor of all processes, including shell/terminal
• exec() makes a process execute a given executable
• exit() terminates a process
• wait() causes a parent to block until child terminates
• Many variants of the above system calls exist in language libraries
with different arguments

4
Process creation: fork
• Parent process calls “fork” system call to create (spawn) a new process
• New child process created with new PID
• Memory image of parent is copied into that of child
• Parent and child run different copies of same code

Parent memory image copied to create


child memory image

Image credit: OSTEP


What happens after fork?
• Parent and child resume execution in their copies of the code
• Child starts executing with a return value of 0 from fork
• Parent resumes executing with a return value equal to child PID
• Parent and child run independently
• Any changes in parent’s data after fork does not impact child
int ret = fork() Child resumes int ret = fork()
if(ret == 0) { here if(ret == 0) {
print “I am child” Parent resumes print “I am child”
} here }
else if(ret > 0) { else if(ret > 0) {
print “I am parent” print “I am parent”
} }
Image credit: OSTEP
Example code with fork
• Parent and child run independently and print to screen
• Order of execution of parent and child can vary

8
Image credit: OSTEP
Example code with fork int ret = fork()
int x = 1
• What values of x are printed? if(ret == 0) {
• Parent and child both start with their own print “I am child”
independent copies of variable x in their x = x+1
print x
memory images
}
• Child increments its copy of x, prints 2 else if(ret > 0) {
• Parent decrements its copy of x, prints 0 print “I am parent”
x = x -1
print x
}

Image credit: CSAPP


Example code with nested fork fork()
fork()
• Total 4 processes (1 parent + 3 child) print hello
exit
• Hello printed 4 times

Image credit: CSAPP


Exit system call
• When a process finishes execution, it calls exit system call to
terminate
• OS switches the process out and never runs it again
• Exit is automatically called at end of main
• Exiting process cannot clean up its memory, and memory must be
freed up by someone else (why? More on this later.)
• Terminated process exists in a zombie state
• How are zombies cleaned up?
Wait system call
• Parent calls wait system call to reap (clean up …
memory of) a zombie child int ret = fork()
if(ret == 0) {
• Wait cleans up memory of one terminated child
print “I am child”
and returns in parent process exit()
• If child still running, wait system call blocks }
parent until child exits else if(ret > 0) {
• If child terminated already, wait reaps child and print “I am parent”
returns immediately wait()
• If parent with no child calls wait, it returns }
immediately without reaping anything …
More on wait
• Wait system call variant waitpid reaps a specific child with a given PID,
while regular wait reaps any terminated child
• Read man pages for more details on arguments to waitpid and wait
• Wait system call “reaps” one dead child at a time (in any order)
• Every fork must be followed by call to wait at some point in parent
• What if parent has exited while child is still running?
• Child will continue to run, becomes orphan
• Orphans adopted by init process, reaped by init when they terminate
• If parent forks children, but does not bother calling wait for long time,
system memory fills up with zombies
• Common programming error, exhausts system memory
14
Image credit: OSTEP
Example code with fork and wait
• Order of printing of child and parent is deterministic now
• Why? Parent waits until child prints and exits, then prints

Image credit: OSTEP


Exec system call
• Isn’t it impractical to run the same code in all
processes? …
int ret = fork();
• Sometimes parent creates child to do similar work.. if(ret == 0) {
• .. but other times, child may want to run different code exec(“some_executable”)
}
• Child process uses “exec” system call to get a new else if(ret > 0) {
“memory image” print “I am parent”
• Allows a process to switch to running different code }
• Exec system call takes another executable as argument …
• Memory image is reinitialized with new executable, new
code, data, stack, heap, …
17
Image credit: OSTEP
Example code with exec
• Many variants of exec system call (execvp used in example), which
differ in the arguments provided (read more in man pages)
• If exec successful, child gets new memory image, never comes back to
the code in old memory image after exec
• Print statement after exec doesn’t run if exec successful
• If exec unsuccessful, reverts back to original memory image

Image credit: OSTEP


Shell / Terminal
• After bootup, the init process is first process created
• The init process spawns a shell like bash
• All future processes are created by forking from existing
processes like init or shell
• Shell reads user command, forks a child, execs the command
executable, waits for it to finish, and reads next command
• Common commands like ls, echo, cat are all readily
available executables that are simply exec-ed by the shell

19
$echo hello
hello
Example shell code $
• How does the shell run a user command?
do forever {
• Read input from user input(command)
• Shell process forks a child process
int ret = fork()
• Child process runs exec with “echo”
program executable as argument, calls exit if(ret == 0) {
when done exec(command)
• Parent shell calls wait, blocks till child }
terminates, reaps it, goes back for next else {
input wait()
}
}
More on shell and commands
• Some commands already exist as programs written by OS developers
and compiled into executables
• Shell runs such command by simply calling exec in child process
• Some commands are implemented directly in shell code itself
• Think: why doesn’t shell exec command directly? Why fork a child?
• Do we want the shell program code to be rewritten fully?
• For “cd” command, “chdir” system call used to change directory of
parent process itself, no child process is forked. Why?
• Every process has a current working directory
• Do we want to change directory of some child process or shell itself?
$sleep 10 &
$
Foreground and background execution
• By default, user command runs in foreground, shell cannot accept next
command until previous one finishes
• Background execution: when we type command followed by &
• Shell starts child to run command, but does not wait for command to finish
• Background processes reaped at a later time by shell
• When? Periodically? When next input is typed?
• How? There is a way to invoke wait where parent is not blocked even if child has
not exited (explore it on your own)
• It is also possible to run multiple commands in the foreground
• One after the other serially (next command starts after previous finishes)
• Or, all start at same time in parallel
• Explore how such things can be done in the standard Linux shell 22
$ls > foo.txt
$
I/O redirection
• Every process has some I/O channels (“files”) open, which can be
accessed by file descriptors
• STDIN, STDOUT, STDERR open by default for all processes
• Parent shell can manipulate these file descriptors of child before
exec in order to do things like I/O redirection
• E.g., output redirection is done by closing the default STDOUT and
opening a regular file in its place
STDIN from keyboard

Process P STDOUT to screen STDOUT to file


STDERR to screen
23
Open uses the first available file
descriptor (STDOUT in this case)

Image credit: OSTEP


Signals
• Signal: a way to send notifications to processes
• Standard signals available in operating systems, each corresponding to a
specific event, and with a specific signal number
• Signal SIGINT sent to process by typing Ctrl+C, SIGSTP for Ctrl+D
• Signal SIGCHLD sent to parent process when child terminates
• SIGTERM and SIGKILL to terminate/kill processes
• System call kill can be used to send a signal from one process to other
• Kill system call can send all signals, not just SIGKILL
• Some restrictions on who can send to whom for isolation and security
• Signals can also be generated by OS for a process, e.g., when it handles
interrupt due to Ctrl+C keyboard event
• Kill command to send signals, e.g., “kill -9 <pid>” sends SIGKILL (#9)
Process groups
• When we type Ctrl+C on keyboard, which processes get the signal?
• Processes are organized into process groups, every process belongs
by default to process group of its parent
• When signal is sent to a process, it is delivered to all processes in its
process group by default
• Example: when we hit Ctrl+C on keyboard, signal sent to all processes
in the foreground process group
• System call setpgid can be used to change process group of signals, to
control signal distribution
Signal handling
• Signals to a process are queued up by OS and delivered when process
is running
• Default behavior defined by OS for a process receiving a signal
• Ignore some signals (e.g., SIGCHLD)
• Terminate when some signals are received (e.g., SIGINT)
• User processes can define their own signal handler functions to be
executed when a signal is received
• Override default behavior defined for a signal
• Some signals (e.g., SIGKILL) cannot be overridden
• Process jumps to signal handler, executes it, resumes if still alive
Examples: sending and catching signals
• Parent sends SIGKILL to child • Default SIGINT hander
using kill system call overridden
• Child runs in infinite loop until • Process prints message before
killed by parent terminating on SIGINT
void sigint_handler(int sig) {
int pid = fork() print “caught signal”
if(pid == 0) { exit()
while(1); //infinite loop }
//terminates on SIGKILL int main() {
} signal(SIGINT, sigint_handler)
//parent …
kill(pid, SIGKILL) }

You might also like