0% found this document useful (0 votes)
4 views24 pages

Fork_Wait_Exec_Code

The document provides examples of process creation and management in C using fork, wait, and waitpid system calls. It illustrates how to create child processes, handle their termination, and retrieve their exit statuses using macros. Additionally, it discusses the limitations of the wait system call and the advantages of using waitpid for specific process management.

Uploaded by

mardiblbiswajit
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)
4 views24 pages

Fork_Wait_Exec_Code

The document provides examples of process creation and management in C using fork, wait, and waitpid system calls. It illustrates how to create child processes, handle their termination, and retrieve their exit statuses using macros. Additionally, it discusses the limitations of the wait system call and the advantages of using waitpid for specific process management.

Uploaded by

mardiblbiswajit
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/ 24

Souvik Kr Parui

Chain of Processes
................................................................................

Example 1:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int pid;
int n=4;

for (int i = 1; i < n; i++) {


pid = fork();

if (pid > 0) {
// Print the parent process
printf("Parent process ID is %d\n", getpid());
break;
}
else {
// Print the child process
printf("Child process ID is %d\n", getpid());
}
}

return 0;
}

Output :
Parent process ID is 8678
Child process ID is 8679
Parent process ID is 8679
Child process ID is 8680
Parent process ID is 8680
Child process ID is 8681

Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
int n = 4;

for (int i = 1; i < n; i++) {


pid_t child_pid = fork();

if (child_pid == -1) {
// Fork failed
perror("fork");
}

if (child_pid == 0) {
// Child process
printf("Child %d with PID %d is created. Parent PID %d\n", i ,
getpid(), getppid());
}
else {
// Parent process
printf("Parent PID: %d\n", getpid());
// Wait for the child process to finish before creating the next one
wait(NULL);
break; // Prevent the parent from creating additional children
}
}

return 0;
}

Output:
Parent PID: 15385
Child 1 with PID 15386 is created. Parent PID 15385
Parent PID: 15386
Child 2 with PID 15388 is created. Parent PID 15386
Parent PID: 15388
Child 3 with PID 15389 is created. Parent PID 15388

Example 3:
Creates a chain of n processes, where n is a command line argument.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
pid_t childpid = 0;
int i, n;
if (argc != 2)
{/* check for valid number of
command-line arguments */
fprintf(stderr, "Usage: %s processes\n", argv[0]);
return 1;
}
n = atoi(argv[1]);
for (i = 1; i < n; i++)
if (childpid=fork())
break;
fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n", i,
(long)getpid(), (long)getppid(), (long)childpid);
return 0;
}

------------------------------------------------------------------
Fan of Processes

Example 1:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
for (int i = 1; i < 4; i++) {
if (fork() == 0) {
printf("child pid %d from the parent pid %d\n", getpid(),
getppid());

exit(0);
}
}
}

Output:
child pid 2833 from the parent pid 2832
child pid 2834 from the parent pid 2832
child pid 2835 from the parent pid 2832

Example 2:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
int n = 4; // Number of child processes to create

printf("Parent process ID: %d\n", getpid());

for (int i = 1; i < n; i++) {


pid_t child_pid = fork();

if (child_pid == -1) {
// Fork failed
perror("Fork failed");
return 1;
} else if (child_pid == 0) {
// Child process
printf("Child process %d with ID: %d and Parent ID: %d\n", i,
getpid(), getppid());

// Exit the child process


return 0;
} else {
// Parent process Wait for the child process to finish before
creating the next one
wait(NULL);
}
}

// Code executed only by the parent process


printf("All child processes have completed.\n");

return 0;
}

Output:
Parent process ID: 5800
Child process 1 with ID: 5801 and Parent ID: 5800
Child process 2 with ID: 5802 and Parent ID: 5800
Child process 3 with ID: 5803 and Parent ID: 5800
All child processes have completed.

Example 3:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main (int argc, char *argv[]) {


pid_t childpid = 0;
int i, n;
if (argc != 2){
/* check for valid number of command-line
arguments */
fprintf(stderr, "Usage: %s processes\n", argv
[0]);
return 1;
}
n = atoi(argv[1]);
for (i = 1; i < n; i++)
if ((childpid = fork()) <= 0)
break;
fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n",i,
(long)getpid(), (long)getppid(), (long)childpid);
return 0;
}

Explain what happens when you replace the test (childpid = fork()) <= 0 of the
previous program with (childpid = fork()) == -1 ?
Draw a suitable diagram labelling the circles with the actual process.

--------------------------------------------------------------------------------
--

wait & waitpid

................................................................................
..

wait system call

Example 1 :

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(5);
exit(0);
}
printf("Before wait call \n");
pid_t waitr = wait(NULL); //return childid
printf("Parent executed wait and wait return :%d\n",waitr);
}
Example 2 :

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
pid_t waitr = wait(NULL);
if(waitr==-1){
perror("Error is :");
}
exit(0);
}
printf("I am Parent\n");

//printf("Status=%d\n",status);
}

Example 3:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(5);
exit(0); // Normally Terminated
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);

printf("Status=%d\n",status); //status return 0 because exit(0)


}

status = 32 bit for representation 16 bit is used.


Process termination status (int) 16 bit number
1. status value if child process has normal exit/termination ( exit(0) )

15......8 | 7......0
XXXXXXXX | XXXXXXXX
exitStatus | unused

exit(0) status=0

15......8 | 7......0
00000000 | 00000000
exitStatus | unused

exit(1) status=256

15......8 | 7......0
00000001 | 00000000
exitStatus | unused

2. killed by signal // stopped by signal


15......8 | 7 ......0
unused | X termination signal
|
|-----> core dump flag

kill -9 childpid status = 9 (signal Number)

00000000 | 00001001
unused | termination signal

3. Core dump flag (Segmentation Fault, Floating point exception)

15......8 | 7 ......0
unused | 1 termination signal
|
|-----> core dump flag

Example : Core dump

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());

int *p=NULL;
*p=7;

exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);

printf("Status=%d\n",status);
}

status = 128+11(segmentation fault signal) = 139

--------------------------------------------------------------------------------
------

What will be the output of this code ?

Example 1 :

int main()
{ /* PID of child 3425 */
pid_t childpid,waitreturn; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
waitreturn=wait(NULL);
if (childpid != waitreturn) // 0 != -1 True for child
{
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
printf("Return value of wait=%d\n",waitreturn);
}
return 0;
}

Example 2 :

int main()
{ /* PID of child 3425 */
pid_t childpid,waitreturn; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
waitreturn=wait(NULL);
if (childpid == waitreturn) // True for Parent process
{
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
printf("Return value of wait=%d\n",waitreturn);
}
return 0;
}

Example 3 :

int main()
{ /* PID of child 3425 */
pid_t childpid; /* PID of parent 3424 */
childpid = fork();
// Code executed by both parent and child processes

if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid()); // Code executed by the child
process
}
if (childpid == wait(NULL)) // Code executed by the parent process
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
}
return 0;
}

In the child process (if (childpid == 0)), it prints the Child Process ID using
getpid().
In the parent process (else part), it waits for the child process to terminate
using wait(NULL).
The return value of wait() is the process ID of the terminated child process,
which is printed.

Output :
Child Process ID=3425
Return value of fork=3425
Parent Process ID=3424

Example 4 :

int main()
{ /* PID of child 3425 */
pid_t childpid; /* PID of parent 3424 */
childpid = fork();
if(childpid == 0)
{
printf("Process ID=%ld\n",(long)getpid());
}
if (childpid != wait(NULL))
printf("Return value of fork=%ld\n",(long)childpid);
printf("Process ID=%ld\n",(long)getpid());
}
return 0;
}

................................................................................
......
wait & macro operation

POSIX specifies six macros for testing the childâ€s return status. Each takes
the status value returned by a child to wait or waitpid as a parameter.

#include <sys/wait.h>

WIFEXITED(int stat_val)----------------WEXITSTATUS(int stat_val)


WIFSIGNALED(int stat_val)--------------WTERMSIG(int stat_val)
WIFSTOPPED(int stat_val)---------------WSTOPSIG(int stat_val)
WIFCONTINUED(int stat_val)-------------SIGCONT
Example 1 : If WIFEXITED evaluates to a nonzero value, then WEXITSTATUS
evaluates to the low-order 8 bits returned by the child through _exit(),
exit() or return from main.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());

exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status); // status = 256

if(WIFEXITED(status)) // Condition True : then status return 1 because


exit(1) // Condition False : Killed and stop by signal

printf("status by macro:%d\n",WEXITSTATUS(status)); //status=1


}

Example 2 : If WIFSIGNALED evaluates to a nonzero value, then WTERMSIG evaluates


to the number of the signal that caused the termination.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(50);

exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status);

if(WIFSIGNALED(status)) // Condition True : kill the childpid using signal


then print the signal number status (kill -9 Childpid) // Condition False : not
killed by signal
printf("status by macro:%d\n",WTERMSIG(status));
}

Example 3 : If WIFSTOPPED evaluates to a nonzero value, then WSTOPSIG evaluates


to the number of the signal that caused the child process to stop.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
int status;
pid_t id = fork();

if(id==0)
{
printf("I am child and my pid is :%d\n", getpid());
sleep(50);

exit(1);
}
printf("Before wait call \n");
pid_t waitr = wait(&status);
printf("Parent executed wait and wait return\n",waitr);
printf("Status=%d\n",status);

if(WIFSTOPPED(status)) // Condition True : Stop the childpid using signal


then print the signal number status (kill -STOP Childpid) // Condition False :
not stopped by signal

printf("status by macro:%d\n",WSTOPSIG(status));
}

Limitation of wait() System Call :

It is not possible for the parent to retrieve the signal number during which the
child process has stopped the execution (SIGSTOP(19), SIGTSTP(20)).
Parent wonâ€t be able to get the notification when a stopped child was resumed
by the delivery of a signal (SIGCONT(18), SIGCHLD(17)).
Parent can only wait for first child that terminates. It is not possible to wait
for a particular child.
It is not possible for a non blocking wait so that if no child has yet
terminated, parent get an indication of this fact.

................................................................................
............................................................

waitpid

The waitpid function lets us wait for one particular process, whereas the wait
function returns the status of any terminated child.
The waitpid function provides a nonblocking version of wait. There are times
when we want to fetch a childâ€s status, but we donâ€t want to block.
The waitpid function provides support for job control with the WUNTRACED and
WCONTINUED options.
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *stat_loc, int options);

a pid
a pointer to a location for returning the status
a flag specifying options.

First Parameter :

pid=-1 waits for any child


pid>0 waits for the specific child
pid=0 waits for any child in the same process group
pid<-1 waits for any child in the process group specified by the absolute
value of pid |-2|=2

Note :

wait(NULL) or waitpid(-1, NULL, 0);

int status;
wait(&status) or waitpid(-1, &status, 0);

Third parameter :

can be zero , options = 0 waitpid waits until the child change state.
or
can be the bitwise inclusive OR of the constants: WNOHANG, WUNTRACED,and
WCONTINUED

Example 1 :

/* Program to demonstrate waitpid and exit*/

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>

int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/

if(cpid == 0){
printf("\nchild-1 executing its pid = (%d)\n",getpid());
sleep(10);

printf("Child1 exited\n");
exit(0);
}
else{

cpid2 = fork();
if(cpid2 == -1){
exit(-1);
}
if(cpid2 == 0){
printf("\nchild-2 executing its pid = (%d)\n",getpid());
sleep(5);
printf("Child2 exited\n");
exit(1);
}

printf("\n Parent executing before wait() Parent pid is (%d)\


n",getpid());
ret_pid = waitpid(cpid2, &status, 0);
printf("\n cpid returned is (%d)\n",ret_pid);
printf("\n status is (%d)\n",status);

ret_pid = waitpid(cpid, &status, 0);


printf("\n cpid returned is (%d)\n", ret_pid);
printf("\n status is (%d)\n",status);

printf("\n Parent exited\n");


}

return 0;
}

Example 2 :

/* Program to demonstrate wait and exit*/


/* Use of WNOHANG => This is a non blocking call to waitpid()*/

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
#include <errno.h>

extern int errno;

int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/

if(cpid == 0){ /* This is child process */


printf("\nchild-1 executing its pid = (%d)\n",getpid());
sleep(10);

printf("Child1 exited\n");
exit(0);
}
else{/* This is parent process*/
printf("\n Parent executing before wait() Parent pid is (%d)\
n",getpid());
ret_pid = waitpid(80, &status, WNOHANG);
//ret_pid = waitpid(cpid, &status, 0);
if (ret_pid == -1){
perror("Error is:");
printf("\n waitpid returned error (%d)\n",errno);
}
printf("\n cpid returned is (%d)\n",ret_pid);
printf("\n status is (%d)\n",status);

printf("\n Parent exited\n");


}

return 0;
}

#if 0
refer to below for details on errno
man errno

#endif

Example 3 :
//Using WNOHANG : Nonblocking version of wait. when we want to fetch a childâ€s
status, but we donâ€t want to block.
Parent is not waiting for that child and but parent is execute other line after
waitpid.

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>

int main()
{
pid_t cpid;
pid_t cpid2;
pid_t ret_pid;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child depending on use case*/

if(cpid == 0){
printf("\nchild-1 executing its pid = (%d)\n",getpid());
sleep(10);

printf("Child1 exited\n");
exit(0);
}
else{

cpid2 = fork();
if(cpid2 == -1){
exit(-1);
}
if(cpid2 == 0){
printf("\nchild-2 executing its pid = (%d)\n",getpid());
sleep(5);
printf("Child2 exited\n");
exit(1);
}

printf("\n Parent executing before wait() Parent pid is (%d)\


n",getpid());

do(){
ret_pid = waitpid(cpid2, &status, WNOHANG);
printf("Parent is waiting.......\n");
sleep(10);
} while(ret_pid==0);

perror("error is:");
printf("\n cpid returned is %d\n", ret_pid);
printf("Status=%d\n",status);

printf("\n Parent exited\n");


}

return 0;
}

Example 4:

using WNOHANG|WUNTRACED|WCONTINUED
.....................................

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>

int main()
{
pid_t cpid;
pid_t cpid2;
int status = 0;
cpid = fork();
if(cpid == -1)
exit(-1); /* terminate child */

if(cpid == 0){
printf("\nfirst child executing its pid = (%d)\n",getpid());
sleep(20);
printf("Child pid = %d\n", getpid());
exit(1);
}
else{
cpid2 = fork();
if(cpid2 == 0){
printf("\nsecond child executing its pid = (%d)\n",getpid());
sleep(20);
printf("Child pid = %d\n", getpid());
exit(1);
}
printf("\n Parent executing before wait()\n");
while(1)
{
pid_t id2 = waitpid(cpid, &status, WNOHANG|WUNTRACED|WCONTINUED);
printf("status == %d\n",status);
sleep(1);
if(id2==-1)
{break;}
if(id2>0){
//cpid = wait(&status);
if(WIFEXITED(status)){
printf("The exit status set %d \n", WEXITSTATUS(status));

}
else if (WIFSIGNALED(status)){
printf("The termination signal is %d \n", WTERMSIG(status));
}
else if (WIFSTOPPED(status)){
printf("The stopped signal is : %d \n",WSTOPSIG(status));

}
else if (WIFCONTINUED(status))
printf("The prosess is resume\n");

}
}
}
printf("The parent process completed .......\n");

return 0;
}

kill -STOP childpid


kill -CONT childpid

--------------------------------------------------------------------------------
--------------------------
ZOMBIE

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.

The zombie is actually not a process at all, so canot be killed.


The only reason for a child to memain in the zombie state is the hope that the
parent may eventually call wait or waitpid to pickup the exit status and clear
the process table slot.

Example 1:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{

pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
sleep(30);

}else
{ /* Child process*/
exit(0);
}

return 0;
}

Example 2:
/*
Demonstrate Zombie process
run command on terminal - ps aux | grep Z

Note: If a process is in Zombie state, this means a entry of that process is


still present in process table
*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{

pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
sleep(15);
printf("\nParent Process: I have created child process withID = (%d)\
n",id);
printf("\n Paren process exited\n");

}else
{ /* Child process*/
sleep(5);
printf("\nchild process id is (%d)\n",getpid());
printf("\nThe creator of child process is (%d)\n",getppid());
}

return 0;
}

How to identify Zombie ?


------------------------
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 a.out)

Look into the line that contains defaunct. It is the Zombie with process state
code Z

gcc pp.c //compile


./a.out & // Make the process run in the background //5864 (pid)
pstree -p 5864 // a.out(5864) ------- a.out(5865)
ps aux | grep 5865

After the program terminate, again type the command ps -la.


Is the ZOMBIE exit or not? If not process terminate.

man ps
to read process state information under the heading PROCESS STATE CODES

--------------------------------------------------------------------------------
----------------------------
ORPHAN

When the parent dies first, the child becomes an orphan since the parent is not
just there to pickup the childâ€s exit status.

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.
When it finds one , it makes init/ systemd its parent by changing PPID field of
the child.

Example 1:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{

pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork();
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ /* Parent process*/
exit(0);

}else
{ /* Child process*/
sleep(60);
}

return 0;
}

How to identify Orphan ?


------------------------

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.

./a.out & 5889


pstree -p 5889 // done ./a.out
pstree -p 5889
ps aux | grep a.out
ps -o ppid=5890 // 1
pstree -p 1 // childs of init process

Example 2:
/*
Demonstrate Orphan process (A Process that does not have a parent)
(Reparenting : Finding another parent for the process. Init process becomes
parent)
*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{

pid_t id;
printf("Parent Process : Executed by parent process before fork() - PID =
(%d)\n",getpid());
id = fork(); // from this point of code, the child and parent process both
execute
if (id < 0 ){
printf("\nfork failed\n");
exit(-1);
}
if(id > 0){ // Parent process, killing before child executes
printf("\nParent process exited\n");
return (0);

}else
{ // Child process
printf("\nChild process executing\n");
sleep(10);
printf("\nI am child process, id value is (%d)\n",id) ;
printf("\nchild process id is (%d)\n",getpid());
}

return 0;
}

--------------------------------------------------------------------------------
------------------------------
exec Family of System Calls

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 applications
require the child process to execute code that is different from that of the
parent.
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.

exec Family Series


------------------

The exec: l series: l - a fixed list of arguments


The execl (execl, execlp and execle) functions pass the commandline arguments in
an explicit list and are useful if the number of commandline arguments are known
at compile time.

execl(argument list)
execle(argument list)
execlp(argument list

The exec: v series: v - a variable number of arguments


The execv (execv, execvp and execve) functions pass the commandline arguments in
an argument array.

execv(argument list)
execve(argument list)
execvp(argument list)

The path parameter to execl is the pathname of a process image file specified
either as a fully qualified pathname or relative to the current directory.

exec Family System Call Prototype


---------------------------------

#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 execv(const char *path, char *const argv[]);
int execve (const char *path, char *const argv[], char *const envp[]);
int execvp (const char *file, char *const argv[]);

Example 1 : execl

Main Program : mp.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("\n I am main process pid = (%d)\n",getpid());
execl("./np","arg1","arg2","arg3",NULL);

printf("This line will not be printed... ");

return 0;
}

New Program : np.c

#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])


{
int i;

printf("I am new program called by execl(), my pid is (%d) ",getpid());


printf("\n");
for(i = 0; i < argc; i++){
printf("\n argv[%d] = (%s)\n",i,argv[i]);
}
return 0;
}

Compile the code :

gcc np.c -o np
gcc mp.c -o mp

Run the code :

./mp

Example 2 : execl

Main Program :

#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>

int main()
{
pid_t cpid;
int status = 0;
int num = 5;
cpid = fork();
if(cpid == -1)
exit(0); /* terminate child */

if(cpid == 0){
printf("\nBefore exec\n");
execl("./program2","arg1","arg2",NULL);
printf("\n line is not printed\n");
}
else{
printf("\n Parent executing before wait(), child process created by
parent is = (%d)\n",cpid);
cpid = wait(&status); /* waiting for child process to exit*/
printf("\n wait() in parent done\nParent pid = %d\n", getpid());
printf("\n cpid returned is (%d)\n",cpid);
printf("\n status is (%d)\n",status);
}

return 0;
}

New Program :

#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])


{
int i = 0;

printf("I am new process called by execl() ");


printf("new program pid = (%d)\n",getpid());
for(i = 0; i < argc; i++){
printf("\n argv[%d] = (%s)\n",i,argv[i]);
}
sleep(20);
return 0;
}

Example 3 : execv

Main Program :

/*
Demo to use execv()
*/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("\n Main program p1.c\n");
//A null terminated array of character pointers
char *args[]={"arg1","arg2","arg3",NULL};
execv("./p2",args);
printf("\nThis line is not printed\n");

return 0;
}

New Program :

#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])


{
int i;

printf("I am new program called by execv() ");


printf("\n");
for(i = 0; i < argc; i++){
printf("\n argv[%d] = (%s)\n",i,argv[i]);
}

return 0;
}

Example 4 : execv

Main Program :

New Program :

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

extern char **environ;

int main(int argc, char *argv[]){


int j;
char **ep;

printf("\n executing program2\n");

for (j = 0; j < argc; j++)


printf("argv[%d] = %s\n", j, argv[j]);

for (ep = environ; *ep != NULL; ep++)


printf("environ: %s\n", *ep);

exit(0);
}

--------------------------------------------------------------------------------
------------
Solved Some Problems

Example 1:

P
/ | \
c1 c2 c3
/ \
c4 c5
|
c6
|
c7
Develop a C code to create the following process tree. Display the process ID,
parent ID and return value of fork() for each process.

Use ps utility to verify the is-a-parent relationship?


• Are ypu getting any orphan process case?
• Are you getting any ZOMBIE case?

Code :

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
// Process p creates c1, c2, c3
pid_t c1, c2, c3;

printf("p: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);

c1 = fork();
if (c1 == 0) {
// Process c1
printf("c1: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}

c2 = fork();
if (c2 == 0)
{
// Process c2 creates c4, c5
printf("c2: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);

pid_t c4, c5;

c4 = fork();
if (c4 == 0) {
// Process c4
printf("c4: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}

c5 = fork();
if (c5 == 0) {
// Process c5 creates c6
printf("c5: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);

pid_t c6 = fork();
if (c6 == 0) {
// Process c6 creates c7
printf("c6: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(),
0);

pid_t c7 = fork();
if (c7 == 0) {
// Process c7
printf("c7: PID=%d, PPID=%d, Fork()=%d\n", getpid(),
getppid(), 0);
_exit(0);
}
wait(NULL); // Wait for c7 to finish
exit(0);
}

wait(NULL); // Wait for c6 to finish


exit(0);
}

wait(NULL); // Wait for c4 and c5 to finish


exit(0);
}

c3 = fork();
if (c3 == 0) {
// Process c3
printf("c3: PID=%d, PPID=%d, Fork()=%d\n", getpid(), getppid(), 0);
exit(0);
}

// Wait for all child processes to finish


wait(NULL);
wait(NULL);
wait(NULL);
wait(NULL);
wait(NULL);

return 0;
}

You might also like