Example of waitpid() in use? - c

I know that waitpid() is used to wait for a process to finish, but how would one use it exactly?
Here what I want to do is, create two children and wait for the first child to finish, then kill the second child before exiting.
//Create two children
pid_t child1;
pid_t child2;
child1 = fork();
//wait for child1 to finish, then kill child2
waitpid() ... child1 {
kill(child2) }

Syntax of waitpid():
pid_t waitpid(pid_t pid, int *status, int options);
The value of pid can be:
< -1: Wait for any child process whose process group ID is equal to the absolute value of pid.
-1: Wait for any child process.
0: Wait for any child process whose process group ID is equal to that of the calling process.
> 0: Wait for the child whose process ID is equal to the value of pid.
The value of options is an OR of zero or more of the following constants:
WNOHANG: Return immediately if no child has exited.
WUNTRACED: Also return if a child has stopped. Status for traced children which have stopped is provided even if this option is not specified.
WCONTINUED: Also return if a stopped child has been resumed by delivery of SIGCONT.
For more help, use man waitpid.

The syntax is
pid_t waitpid(pid_t pid, int *statusPtr, int options);
1.where pid is the process of the child it should wait.
2.statusPtr is a pointer to the location where status information for the terminating process is to be stored.
3.specifies optional actions for the waitpid function. Either of the following option flags may be specified, or they can be combined with a bitwise inclusive OR operator:
WNOHANG
WUNTRACED
WCONTINUED
If successful, waitpid returns the process ID of the terminated process whose status was reported. If unsuccessful, a -1 is returned.
benifits over wait
1.Waitpid can used when you have more than one child for the process and you want to wait for particular child to get its execution done before parent resumes
2.waitpid supports job control
3.it supports non blocking of the parent process

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (){
int pid;
int status;
printf("Parent: %d\n", getpid());
pid = fork();
if (pid == 0){
printf("Child %d\n", getpid());
sleep(2);
exit(EXIT_SUCCESS);
}
//Comment from here to...
//Parent waits process pid (child)
waitpid(pid, &status, 0);
//Option is 0 since I check it later
if (WIFSIGNALED(status)){
printf("Error\n");
}
else if (WEXITSTATUS(status)){
printf("Exited Normally\n");
}
//To Here and see the difference
printf("Parent: %d\n", getpid());
return 0;
}

Related

Properly reaping all child processes and collecting exit status

I want to catch all child processes forked by a parent process, then collect the last child's exit status. To that end, I called sigsuspend() to wait for a SIGCHLD signal. When I receive the SIGCHLD signal, then the handler will call waitpid in a loop until it indicates there are no children left to reap. The exit status will be set, and the main will break out of the loop and terminate.
However, I noticed that this is not correct, as all the children aren't always reaped. How can I fix this?
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
volatile sig_atomic_t exit_stat;
// Signal Handler
void sigchld_handler(int sig) {
pid_t pid;
int status;
while(1) {
pid = waitpid(-1, &status, WNOHANG);
if(pid <= 0) {break;}
if(WIFEXITED(status)) {
printf("%s", "Exited correctly.");
}
else {
printf("%s", "Bad exit.");
}
}
exit_stat = status;
}
// Executing code.
int main() {
signal(SIGCHLD, sigchld_handler);
sigset_t mask_child;
sigset_t old_mask;
sigemptyset(&mask_child);
sigaddset(&mask_child, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask_child, &old_mask);
for(int i = 0; i < 5; i++) {
int child_pid = fork();
if(child_pid != 0) {
//Perform execvp call.
char* argv[] = {"echo", "hi", NULL};
execvp(argv[0], argv);
}
}
while(!exit_stat) {
sigsuspend(&old_mask);
}
return 0;
}
Transferring lightly modified comments into an answer.
The WNOHANG option to waitpid() means "return immediately if there are no children left, OR if there are children left but they're still running". If you really want to wait for all children to exit, either omit the WNOHANG option to waitpid() or simply use wait() instead. Note that if there were tasks launched in the background, they may not terminate for a very long time, if ever. It also depends on the context whether 'the last child to die' is the correct one to report on. It is possible to imagine scenarios where that is not appropriate.
You're right, in this instance, I meant that "the last child to die" is the last child that was forked. Can I fix this by adding a simple condition to check if the returned pid of wait == the pid of the last forked child?
If you're interested in the last child in the most recent pipeline (e.g. ls | grep … | sort … | wc and you want to wait for wc), then you know the PID for wc, and you can use waitpid(wc_pid, &status, 0) to wait for that process specifically to die. Or you can use your loop to collect bodies until you either find the body of wc or get 'no dead processes left'. At that point, you can decide to wait specifically for the wc PID, or (better) use waitpid() without WNOHANG (or use wait()) until some process dies — and again you can decide whether it was wc or not, and if not, repeat the WNOHANG corpse collection process to collect any zombies. Repeat until you do find the corpse of wc.
And also, you said that background tasks may not terminate for a long time. By this, do you mean that waitpid(-1, &status, 0) will completely suspend all processes until a child is ready to be reaped?
waitpid(-1, &status, 0); will make the parent process wait indefinitely until some child process dies, or it will return because there are no children left to wait for (which indicates there was a housekeeping error; children should not die without the parent knowing).
Note that using a 'wait for any child' loop avoids leaving zombies around (children that have died but not been waited for). This is generally a good idea. But capturing when the child you're currently interested in dies ensures that your shell doesn't hang around waiting when it wasn't necessary. So, you need to capture both the PID and the exit status of the dead child processes.

Parameters of the waitpid()

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int status;
int pid = fork();assigned to variable "pid"
if(pid == 0)
{
printf("I am the child with pid = %d\n", getpid());
}
else
{
printf("I am the parent with pid = %d\n", getpid());
waitpid(pid, &status, 0); // line 51
}
return 0;
}
In line number 51, please clarify the "pid" parameter. what will this process wait for?
fork returns 0 for the child process, -1 on error, and something else for the parent process. The else begins the part for the parent process, that means pid in waitpid contains the child's PID.
Citing man wait:
The waitpid() system call suspends execution of the calling
process
until a child specified by pid argument has changed state. By default,
waitpid() waits only for terminated children, but this behavior is mod-
ifiable via the options argument [...]
In short, waitpid waits for the child process to terminate.
If the fork is successful, fork returns 0 to the child, and returns to the parent the (positive) pid of the newly forked child process. In this statement, the parent waits the child's termination.
on success fork will return child id to parent and 0 to child,
waitpid(pid, &status, 0);
parameter.. ) pid - particular child ID.
parameter.. ) &status - exit status that will send to parent by child
parameter.. ) option
0 - option is indicated that
parent will wait till child is terminated.

Linux /proc/PID dir of child stays alive after parent kills child

It seems that if I create a process, fork it and send a SIGHUP from the parent to the child, the child dies but it's "/proc/PID" dir doesn't dissappear until the parent also dies.
(See code below).
What is the right way to let the parent check if the child is dead ?
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
void testprocdir(pid_t pid) {
struct stat sb;
char path[1024];
sprintf(path,"/proc/%d",pid);
if(stat(path, &sb)==-1 && errno == ENOENT) {
printf("%s does not exist\n", path);
} else {
printf("%s exists\n", path);
}
}
int main(int argc,char **argv) {
pid_t parent,child;
parent=getpid();
printf("I am %d\n",parent);
child=fork();
switch(child) {
case -1:
printf("Forking failed\n");
return 2;
case 0:
parent=getppid();
child=getpid();
printf("I am the child (%d) and my parent is %d\n", child, parent);
while(1) { sleep(1); printf("I am the child and I have slept 1s\n");}
printf("This line should not be visible\n");
}
sleep(1); //make sure kid is in the while loop
printf("I am the parent (%d) and my kid is %d\n", parent, child);
kill(child,SIGHUP);
testprocdir(parent);
printf("Waiting 5s before testing if the procdir of the child (/proc/%d) is removed\n",child);
sleep(5);
testprocdir(child);
return 0;
}
You could use the wait family of system-calls.
fork returns the PID of the child process in the parent process, and 0 in the child process.
man waitpid should provide more than enough direction beyond that to call waitpid in the parent, allowing you to check that child process or all child processes ― including the ability to allow the parent to continue executing if the child is still alive or stop all execution in the parent until the child is dead.
I will start with some concepts:
The OS will keep a child process' entry in the process table (including exit status) around until the parent calls waitpid (or another wait-family function) or until the parent exits (at which point the status is collected by the init process). This is what a "zombie" process is: a process that has exited by is still resident in the process table for exactly this purpose. The process' entry in the table should go away after the first call to waitpid.
Also, from the man page :
A child that terminates, but has not been waited for becomes a "zombie". The kernel maintains a minimal set of information about the zombie process (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child.
So, by using the wait family of functions you can examine the status of child process.
There are some macros also that can be used with with wait family of functions to examine the status of child process like WEXITSTATUS, WIFSIGNALED, WIFEXITED etc .

How can parents waits all child processes finish then exit when it receives SIGINT?

I'm writing a multi process program in C.
I hope parents process can wait all child processes finish then exit when
it receives SIGINT.
I have two questions.
How can parents record each pid of child process it forked.
Child process may finish before recording function run on
main process.
If parents has no idea about how many child processes it has. How can he wait
all child process finish.
Thanks in advance.
You record the pid of child processes as you fork them (if required).
call waitpid in a loop with pid = 0 it will either return a pid of a process that exited or return -1 and if errno = ECHILD you have no slaves left.
Keep calling wait(2) in a loop. Every time wait() returns, you'll get back the PID of the exited child and its status. The status will tell you, whether it exited normally (with an exit code) or due to a signal. Something like this (not tested):
#include <sys/types.h>
#include <sys/wait.h>
...
pid_t pid;
int status;
...
while ((pid = wait(&status)) > 0) {
printf("Child %lu ", (unsigned long)pid);
if (WIFEXITED(status))
printf("exited with status %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("killed by signal %d\n", WTERMSIG(status));
else if (WIFSTOPPED(status))
printf("stopped by signal %d\n", WSTOPSIG(status));
else if (WIFCONTINUED(status))
printf("resumed\n");
else
warnx("wait(2) returned for no discernible reason");
}

What exactly does fork return?

On success, the PID of the child
process is returned in the parent’s
thread of execution, and a 0 is
returned in the child’s thread of execution.
p = fork();
I'm confused at its manual page,is p equal to 0 or PID?
I'm not sure how the manual can be any clearer! fork() creates a new process, so you now have two identical processes. To distinguish between them, the return value of fork() differs. In the original process, you get the PID of the child process. In the child process, you get 0.
So a canonical use is as follows:
p = fork();
if (0 == p)
{
// We're the child process
}
else if (p > 0)
{
// We're the parent process
}
else
{
// We're the parent process, but child couldn't be created
}
p = fork();
/* assume no errors */
/* you now have two */
/* programs running */
--------------------
if (p > 0) { | if (p == 0) {
printf("parent\n"); | printf("child\n");
... | ...
Processes are structured in a directed tree where you only know your single-parent (getppid()). In short, fork() returns -1 on error like many other system functions, non-zero value is useful for initiator of the fork call (the parent) to know its new-child pid.
Nothing is as good as example:
/* fork/getpid test */
#include <sys/types.h>
#include <unistd.h> /* fork(), getpid() */
#include <stdio.h>
int main(int argc, char* argv[])
{
int pid;
printf("Entry point: my pid is %d, parent pid is %d\n",
getpid(), getppid());
pid = fork();
if (pid == 0) {
printf("Child: my pid is %d, parent pid is %d\n",
getpid(), getppid());
}
else if (pid > 0) {
printf("Parent: my pid is %d, parent pid is %d, my child pid is %d\n",
getpid(), getppid(), pid);
}
else {
printf("Parent: oops! can not create a child (my pid is %d)\n",
getpid());
}
return 0;
}
And the result (bash is pid 2249, in this case):
Entry point: my pid is 16051, parent pid is 2249
Parent: my pid is 16051, parent pid is 2249, my child pid is 16052
Child: my pid is 16052, parent pid is 16051
If you need to share some resources (files, parent pid, etc.) between parent and child, look at clone() (for GNU C library, and maybe others)
Once fork is executed, you have two processes. The call returns different values to each process.
If you do something like this
int f;
f = fork();
if (f == 0) {
printf("I am the child\n");
} else {
printf("I am the parent and the childs pid is %d\n",f);
}
You will see both the messages printed. They're being printed by two separate processes. This is they way you can differentiate between the two processes created.
This is the cool part. It's equal to BOTH.
Well, not really. But once fork returns, you now have two copies of your program running! Two processes. You can sort of think of them as alternate universes. In one, the return value is 0. In the other, it's the ID of the new process!
Usually you will have something like this:
p = fork();
if (p == 0){
printf("I am a child process!\n");
//Do child things
}
else {
printf("I am the parent process! Child is number %d\n", p);
//Do parenty things
}
In this case, both strings will get printed, but by different processes!
fork() is invoked in the parent process. Then a child process is spawned. By the time the child process spawns, fork() has finished its execution.
At this point, fork() is ready to return, but it returns a different value depending on whether it's in the parent or child. In the child process, it returns 0, and in the parent process/thread, it returns the child's process ID.
Fork creates a duplicate process and a new process context. When it returns a 0 value it means that a child process is running, but when it returns another value that means a parent process is running. We usually use wait statement so that a child process completes and parent process starts executing.
I think that it works like this:
when pid = fork(), the code should be executed two times, one is in current process, one is in child process.
So it explains why if/else both execute.
And the order is, first current process, and then execute the child.

Resources