11 UnixProcessesPPWC
11 UnixProcessesPPWC
B. M. Harwani
Practical C Programming
Packt Publishing
C compiler
+ The C compiler translates each source file into an object file.
+ The compiler then links the individual object files with the necessary li-
braries to produce an executable module.
+ When a program is run or executed, the operating system copies the
executable module into a program image in main memory.
allocation from
malloc family
HEAP
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
Neither the getpid nor the getppid functions can return an
error.
Example
#include <stdio.h>
#include <unistd.h>
int main (void) {
printf("I am process %ld\n", (long)getpid());
printf("My parent is %ld\n", (long)getppid());
return 0;
} PPWC, CSE 3541 fork-exec-wait
Process State
running done
selected I/O request
to run
process created quantum
expired
new ready blocked
I/O complete
running done
selected I/O request
to run
process created quantum
expired
new ready blocked
I/O complete
state meaning
new being created
ready waiting to be assigned to a processor
running instructions are being executed
blocked waiting for an event such as I/O
done finished
PPWC, CSE 3541 fork-exec-wait
ps Utility
pid_t fork(void);
pid_t fork(void);
#include <stdio.h>
#include <unistd.h>
int main(void) {
int x;
x = 0;
fork();
x = 1;
printf("I am process %ld and my x
is %d\n", (long)getpid(), x);
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main(void) {
int x;
x = 0;
fork();
x = 1;
printf("I am process %ld and my x
is %d\n", (long)getpid(), x);
return 0;
}
In the above program, both parent and child execute the x = 1 assignment
statement after returning from fork.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) /* child code */
printf("I am child %ld\n", (long)getpid());
else /* parent code */
printf("I am parent %ld\n", (long)getpid());
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) /* child code */
printf("I am child %ld\n", (long)getpid());
else /* parent code */
printf("I am parent %ld\n", (long)getpid());
return 0;
}
After fork in the above program, the parent and child output their respective
process IDs.
PPWC, CSE 3541 fork-exec-wait
Find the Output
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
pid_t mypid;
mypid = getpid();
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) /* child code */
printf("I am child %ld, ID = %ld\n", (long)
getpid(), (long)mypid);
else /* parent code */
printf("I am parent %ld, ID = %ld\n", (long)
getpid(), (long)mypid);
return 0;
}
PPWC, CSE 3541 fork-exec-wait
Find the Output
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void) {
pid_t childpid;
pid_t mypid;
mypid = getpid();
childpid = fork();
if (childpid == -1) {
perror("Failed to fork");
return 1;
}
if (childpid == 0) /* child code */
printf("I am child %ld, ID = %ld\n", (long)
getpid(), (long)mypid);
else /* parent code */
printf("I am parent %ld, ID = %ld\n", (long)
getpid(), (long)mypid);
return 0;
}
PPWC, CSE 3541 fork-exec-wait
Chain of n=4 Processes
1
+ A graph representing the chain of pro-
cesses, when n is 4.
1 2 3
(childpid = fork()) == -1
Draw a suitable diagram labelling the circles with the actual pro-
cess.
(childpid = fork()) == -1
2a 2b
3a 3b 3c 3d
- The child does not inherit directory change notifications from its parent.
- The child does not receive a signal when its parent terminates.
- The termination signal of the child is always SIGCHLD.
- The port access permission bits set by ioperm (ioperm - set port in-
put/output permissions) are not inherited by the child
- The child process is created with a single thread-the one that called
fork(). The entire virtual address space of the parent is replicated in
the child, including the states of mutexes, condition variables, and other
pthreads objects.
- The child inherits copies of the parent’s set of open file descriptors.
Each file descriptor in the child refers to the same open file description
as the corresponding file descriptor in the parent.
- The child inherits copies of the parent’s set of open message queue
descriptors.
- The child inherits copies of the parent’s set of open directory streams.
- The operating system records the process status and resource usage,
notifying the parent in response to a wait function.
- In UNIX, a process does not completely release its resources after ter-
mination until the parent waits for it.
- If its parent is not waiting when the process terminates, the process be-
comes a zombie.
- Implicit return from main (the main function falls off the end)
15 8 7 0
Termination
Killed by a Signal 0 Signal Number
15 8 7 0
15 8 7 0
Two things can be happened, if the the parent doesnot wait for
the child to die.
- If the child dies first, the kernel empties the process address
space but retains the process table entry. The child is said
to be in a zombie state.
- Open two terminal windows. Run the previous slide code in one terminal.
On the other terminal run the command
(ps -la | grep CMD) ; (ps -la | grep [Link])
- Look into the line that contains defaunct. It is the Zombie with process
state code Z
- After the program terminate, again type the command ps -la. Is the
ZOMBIE exit or not? If not process terminate.
- For more man ps to read process state information under the heading
PROCESS STATE CODES
- The kernel clears the process table slot of the parent, but
before doing so, it checks whether there are any process
spawned by the parent that are still alive.
int main()
{
pid_t childpid;
childpid=fork();
if(childpid==-1){
printf("fork error\n");
return 1;
}
else if (childpid==0){
printf("Child:PID=%ld---PPID=%ld\n",(long)getpid(),(long)getppid());
sleep(100);
printf("Child:PID=%ld---PPID=%ld\n",(long)getpid(),(long)getppid());
}
else{
printf("Parent:PID=%ld--PPID=%ld\n",(long)getpid(),(long)getppid());
exit(0);
}
}
- Open two terminal windows. Run the previous slide code in one terminal.
On the other terminal run the command (ps -le | grep CMD) ;
(ps -le | grep <ChildPID>)
- Observe the process id (PID) and parent id (PPID) of the child and parent
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
- The same function may be registered multiple times: it is called once for
each registration.
- These system calls are used to wait for state changes in a child of the
calling process, and obtain information about the child whose state has
changed.
- If a child has already changed state, then these calls return immediately.
Otherwise they block until either a child changes state or a signal handler
interrupts the call.
- When a process creates a child, both parent and child proceed with ex-
ecution from the point of the fork.
- The parent can execute the system calls wait or waitpid to block until
the child finishes.
- The wait function causes the caller to suspend execution until a child’s
status becomes available or until the caller receives a signal.
- A process status most commonly becomes available after termination,
but it can also be available after the process has been stopped.
- wait synopsis
#include <sys/wait.h>
#include <sys/wait.h>
Killed by a Signal
15 8 7 0
Termination
WIFSIGNALED(status) 0 Signal Number
WTERMSIG(status)
Stopped by a Signal
15 8 7 0
Continued by a Signal
15 8 7 0
The parent can only access the 8 least significant bits of the child’s return status.
- Parent can only wait for first child that terminates. It is not
possible to wait for a particular child.
- waitpid synopsis
#include <sys/wait.h>
#include <sys/wait.h>
- If pid = −1, waitpid waits for any child. In this respect, waitpid is
equivalent to wait.
- If pid > 0, waitpid waits for the child whose process ID equals pid.
- If pid = 0, waitpid waits for any child whose process group ID equals
that of the calling process.
- If pid < −1, waitpid waits for any child whose process group ID
equals the absolute value of pid.
- The options = 0 :: The waitpid waits until the child change state.
- The option WNOHANG :: The waitpid will not block if a child specified by
pid is not immediately available. In this case, the return value is 0.
- If it is not NULL, these functions store the return status of the child in this
location.
+ The child returns its status by calling exit, _exit, _Exit or return
from main.
+ The parent can only access the 8 least significant bits of the child’s return
status.
int status;
fc=fork()
Process Ordering Using wait() and fork return
value
fc=fork()
0)
==
f c
if(
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
sc=fork()
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
sc=fork()
0)
= =
c
if(s
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
sc=fork()
0)
= els
c = e
if(s
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
sc=fork()
0)
= els
c = e
if(s
P1
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
sc=fork()
0)
= els
c = e
if(s
wait();
P1
P2
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0)
= els
c = e
if(s
wait();
P1
P2
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0) 0 )
= els =
c = e c=
if(s if(t
wait();
P1
P2
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0) 0 )
= els = els
c = e c= e
if(s if(t
wait();
P1
P2
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0) 0 )
= els = els
c = e c= e
if(s if(t
wait();
P1 P3
P2
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0) 0 )
= els = els
c = e c= e
if(s if(t
wait(); wait();
P1 P3
P2 P4
Process Ordering Using wait() and fork return
value
fc=fork()
0) els
== e
f c
if(
wait();
sc=fork()
tc=fork()
0) 0 )
= els = els
c = e c= e
if(s if(t
wait(); wait();
P1 P3
P2 P4
- The exec family of functions replaces the current process image with a
new process image.
- The fork function creates a copy of the calling process, but many ap-
plications require the child process to execute code that is different from
that of the parent.
- The exec family of functions provides a facility for overlaying the process
image of the calling process with a new image.
- The exec operation replaces the entire address space(text, data, and
stack) with that of the new process.
- Since the stack is also replaced, the call to exec family of functions
donot return unless it results in an error.
- The child executes ( with an exec function) the new program while the
parent continues to execute the original code.
- All exec functions return -1 and set errno if unsuccessful.
- If any of these functions return at all, the call was unsuccessful.
- execl(argument list)
- execle(argument list)
- execlp(argument list
- execv(argument list)
- execve(argument list)
- execvp(argument list)
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg0, ... /*, char *(0) */);
int execle (const char *path, const char *arg0, ... /*, char *(0), char *const
envp[] */);
int execlp (const char *file, const char *arg0, ... /*, char *(0) */);
int execve (const char *path, char *const argv[], char *const envp[]);
#include <unistd.h>
int execl(const char *path, const char *arg0, ... /*, char *(0) */);
return -1 if unsuccessful
on successful no return to the calling process
#include <unistd.h>
int execle (const char *path, const char *arg0, ... /*, char *(0),
char *const envp[] */);
return -1 if unsuccessful
on successful no return to the calling process
int main(void)
{
int err;
err=execle("/usr/bin/wc","wc","execldemo.c",NULL,NULL);
if(err==-1){
perror("Execle Failed\n");
}
return 0;
}
#include <unistd.h>
int execlp (const char *file, const char *arg0, ... /*, char *(0) */
);
return -1 if unsuccessful
on successful no return to the calling process
int main(void)
{
char *temp1,*temp2;
temp1="Funny"; temp2="world";
pid_t pid;
pid=fork();
if(pid==0){
execlp("echo","echo",temp1,temp2,NULL);
printf("Error");
return 1;
}
else{
/* Parent code*/
}
return 0;
}
PPWC, CSE 3541 fork-exec-wait
The execv System Call
- The execv function takes exactly two parameters, a pathname for the
executable and an argument array.
- Used to run a command or executable with any number of arguments.
- Use an execv function with an argument array constructed at run time.
- The execve and execvp are variations on execv; they are similar in
structure to execle and execlp, respectively.
- SYNOPSIS:
#include <unistd.h>
return -1 if unsuccessful
on successful no return to the calling process
int main(void)
{
char *cmdargs[]={"ls", "-l", NULL};
pid_t pid;
pid=fork();
if(pid==0){
execv("/bin/ls",cmdargs);
}
else{
wait(NULL);
printf("chile terminate\n");
}
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
- To run ./[Link] ls
- To run ./[Link] ls -l
#include <unistd.h>
return -1 if unsuccessful
on successful no return to the calling process
int main(void)
{
char *cmdargs[]={"ls", "-l", NULL};
pid_t pid;
pid=fork();
if(pid==0){
execvp("ls",cmdargs);
}
else{
wait(NULL);
printf("chile terminate\n");
}
return 0;
}
#include <unistd.h>
return -1 if unsuccessful
on successful no return to the calling process
int main(void)
{
char *cmdargs[]={"ls", "-l", NULL};
pid_t pid;
pid=fork();
if(pid==0){
execve("/bin/ls", cmdargs, NULL);
}
else{
wait(NULL);
printf("chile terminate\n");
}
return 0;
}
NOTE::
- If the process is initiated by execl, execlp, execv or execvp, then
the process inherits the environment list of the process just before the
execution of exec.
- The execle and execve functions specifically set the environment list.
#include <stdio.h>
int main(void) {
int i;
printf("The environment list follows:\n");
for(i = 0; environ[i] != NULL; i++){
sleep(2);
printf("environ[%d]: %s\n", i, environ[i]);
}
return 0;
}
Daemon
- A daemon is a background process that normally runs indefinitely.
- The UNIX operating system relies on many daemon processes to per-
form routine tasks.