A system call is a low-level functionality provided by the operating system which allows users to communicate with the operating system to perform operations that require high-level privileges, such as updating device drivers, writing data to a file, etc.
waitpid()
system callThis system call waits for a specific process to finish its execution. This system call can be accessed using our C programs' library sys/wait.h
.
Let's understand how the waitpid()
function works with the help of a diagram.
The diagram shows that we have a parent process with 3 child processes, namely, Child1
, Child2
, and Child3
. If we want the parent to wait for a specific child, we could use the waitpid()
function.
In the diagram above, we made the parent process wait for Child1
to finish its execution using the function. When the parent process is called, the waitpid()
function gets Child1
is terminated.
If we were to replace the process in the waitpid()
function with Child3
, then the parent would only continue when Child3
had terminated.
Hence, we see that we can use the waitpid()
function to make parent processes wait for a specific child process before continuing execution.
Below, we can see the syntax for the waitpid()
system call.
pid_t waitpid(pid_t pid, int *status_ptr, int options);
Let's discuss the three arguments that we provide to the system call.
pid
: Here, we provide the process ID of the process we want to wait for. If the provided pid
is 0, it will wait for any arbitrary child to finish.
status_ptr
: This is an integer pointer used to access the child's exit value. If we want to ignore the exit value, we can use NULL
here.
options
: Here, we can add additional flags to modify the function's behavior. The various flags are discussed below:
WCONTINUED
: It is used to report the status of any child process that has been terminated and those that have resumed their execution after being stopped.
WNOHANG
: It is used when we want to retrieve the status information immediately when the system call is executed. If the status information is not available, it returns an error.
WUNTRACED
: It is used to report any child process that has stopped or terminated.'
Now that we have gone through the syntax, let's discuss what the system call returns after executing.
The system call will return the process ID of the child process that was terminated. If there is any error while waiting for the child process via the waitpid()
system call, it will return -1
, which corresponds to an error.
Now that we have understood what the waitpid()
system call is, let's look at a C program that shows us how we can implement it in programs.
In the program, we have created 4 processes, 3 children, and 1 parent, via two fork()
system calls. We make the parent wait for only one of the child processes, which we named Child2
before it finishes its execution.
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main(){ int cpid = fork(); int cpid2 = fork(); if(cpid != 0 && cpid2 != 0){ int waitPID = 0; int status; printf("\nParent: I am going to wait for the process with process ID: %d\n", cpid2); while(waitPID == 0){ waitPID = waitpid(cpid2, &status, WNOHANG); } printf("\nParent: Waited for child, the return value of waitpid(): %d\n", waitPID); printf("\nParent: The exit code of terminated child: %d\n", WEXITSTATUS(status)); exit(1); } else if(cpid == 0 && cpid2 != 0){ printf("\nChild1: My process ID is: %d, and my exit code is 1\n", getpid()); exit(1); } else if(cpid != 0 && cpid2 == 0){ printf("\nChild2: My process ID is: %d, and my exit code is 2\n", getpid()); exit(2); } else{ printf("\nChild3: My process ID is: %d, and my exit code is 3\n", getpid()); exit(3); } return 0; }
When we run the program, we see that the parent process always prints its second statement after the child process named Child2
has finished its execution. Hence it successfully waits for the child process to finish before continuing.
We can also verify that it waited for the correct child process by comparing the return value of the waitpid()
system call with the process ID of the children's processes.
Lines 7–8: We create four processes via two fork()
system calls.
Lines 10–22: Here, we write the code for the parent process, which waits for one of the child processes to finish before continuing from where it called the waitpid()
system call.
Lines 15–17: We call the waitpid()
system call and use the WNOHANG
option. We use a while
loop that breaks when the system call's return value is non-zero, indicating a child process has finished.
Lines 19–20: After the parent waits for the child process, it prints the exit status of the child process and the return value of the waitpid()
system call.
Lines 23–34: Here, we write the codes for the children processes. We name them Child1
, Child2
, and Child3
. Each child will print its PID and its exit code before exiting.
Now that we have understood what the waitpid()
system call is and how it is used in C programs, let's test ourselves by solving the quiz below.
What process ID should you pass to waitpid()
if you want to wait for any child process to finish its execution?
0
1
-1
Free Resources