How does wait() work in Linux? - linux

Can anyone please explain why the output is like this? I am very much confused about how these processes are being executed (in which order?) and also about waitpid()/wait().
Here is the code:
#include<stdio.h>
main()
{
int pid1, pid2, pid3;
pid1=fork();
if(pid1 == 0){
printf("PID of child 1 is :%d\n",getpid());
//sleep(2);
}
pid2=fork();
if(pid2 == 0){
printf("PID of child 2 is :%d\n",getpid());
//sleep(2);
}
pid3=fork();
if(pid3 == 0){
printf("PID of child 3 is :%d\n",getpid());
//sleep(2);
}
else{
printf("PID of parent is :%d\n",getpid());
waitpid(pid1,0,0);
waitpid(pid2,0,0);
waitpid(pid3,0,0);
}
}
Actual output:
PID of child 1 is :4963
PID of parent is :4962
PID of parent is :4963
PID of child 2 is :4966
PID of parent is :4966
PID of child 2 is :4964
PID of parent is :4964
PID of child 3 is :4967
PID of child 3 is :4965
PID of child 3 is :4969
PID of child 3 is :4968
Expected output:
PID of parent because pid1 is not 0 and never be 0 here.
Then waits until pid1 i.e child1 gets terminated and prints PID of child 1
Then right now child2 and child3 are not forked yet so they are skipped
Then again PID of parent, pid of child1, pid of child2
Then PID of parent, pid of child1, pid of child2 and pid of child3.
So where am I going wrong please?

Here we go...
pid1=fork()
At this point two processes are going. The parent [PID 4962] and the child that was just spawned [PID 4963]. The parent has pid1 = 4963 [the child's PID], and the child [child1] has pid1 = 0. So, the child will print out:
"PID of child 1 is: 4963"
And both processes go on their merry way until they get to:
pid2=fork()
Here, The parent [PID 4962] and child1 [PID 4963] both spawn a child process. We will call the child that the original parent spawns child2 [maybe PID 4964] and the child that child1 spawns, we will call child1_1 [maybe PID 4966]. Now, the original parent has
pid2 = 4964 [maybe] and child2 has pid2 = 0. Child1 has pid2 = 4966 [maybe] and child1_1 has pid2 = 0. Thus, both child2 and child1_1 will print something out:
"PID of child 2 is: 4966"
"PID of child 2 is: 4964"
Now, ALL of those processes get to this:
pid3=fork()
Ouch.
The original parent, child1, child2, and child1_1 all spawn a child process. What you
ultimately end up with is something like this:
For the original parent, child1, child2, and child1_1, pid3 != 0
For their four child processes, pid3 == 0
So, those four child processes all report their PIDs like this:
"PID of child 3 is: xxxx"
But original parent [4962], child1 [4963], child2 [maybe 4964], and child1_1 [maybe 4966]
print:
"PID of parent is: xxxx"
and then wait for their child processes with PIDs pid1, pid2, and pid3 to return.
Keep in mind that all of these processes are running concurrently, and that explains
why you cannot necessarily predict the order in which the print statements will
be carried out.

Related

Understanding fork()

i have a question about this Code:
int id = fork();
if (id != 0)
fork();
printf("FORK: %d\n PID: %d\n PPID:%d\n", id, getpid(), getppid());
}
This is an example Output:
FORK: 5888
PID: 5887
PPID:5239
FORK: 0
PID: 5888
PPID:5887
FORK: 5888
PID: 5889
PPID:5887
I understand the code like this:
The parent process creates with int id = fork(); another process.
The parent process thus has the process ID of the child process as the return value in id and the child process has a value of 0.
With the condition if (id != 0) { fork (); } A child process WILL be created again in the parent process.
Thus, the parent process has two "children".
What confuses me about the output:
Shouldn't two of the three processes (with the PID 5888 and 5889) have a value of 0 in the fork() since both are child processes?
Also, the process with ID 5889 in the fork() has the process id 5888, but wouldn't that mean that 5888 is a child of 5889?
I probably just don't quite understand the principle of fork(), but I would still be grateful for any help.
They should both have id = 0 but you didn't assign the id in the second fork.
For the second question the pids do not have a particular order of assignment and are managed entirely by the kernel.

How many child processes can a parent spawn before becoming infeasible?

I'm a C programmer learning about fork(), exec(), and wait() for the first time. I'm also whiteboarding a Standard C program which will run on Linux and potentially need a lot of child processes. What I can't gauge is... how many child processes are too many for one parent to spawn and then wait upon?
Suppose my code looked like this:
pid_t status[ LARGENUMBER ];
status[0] = fork();
if( status[0] == 0 )
{
// I am the child
exec("./newCode01.c");
}
status[1] = fork();
if( status[1] == 0 )
{
// child
exec("./newCode02.c");
}
...etc...
wait(status[0]);
wait(status[1]);
...and so on....
Obviously, the larger LARGENUMBER is, the greater the chance that the parent is still fork() ing while children are segfaulting or becoming zombies or whatever.
So this implementation seems problematic to me. As I understand it, the parent can only wait() for one child at a time? What if LARGENUMBER is huge, and the time gap between running status[0] = fork(); and wait(status[0]); is substantial? What if the child has run, becomes a zombie, and been terminated by the OS somehow in that time? Will the parent then wait(status[0]) forever?
In the above example, there must be some standard or guideline to how big LARGENUMBER can be. Or is my approach all wrong?
#define LARGENUMBER 1
#define LARGENUMBER 10
#define LARGENUMBER 100
#define LARGENUMBER 1000
#define LARGENUMBER ???
I want to play with this, but my instinct is to ask for advice before I invest the development time into a program which may or may not turn out to be infeasible. Any advice/experience is appreciated.
If you read the documentation of wait, you would know that
If status information is available prior to the call to wait(), return will be immediate.
That means, if the child has already terminated, wait() will return immediately.
The OS will not remove the information from the process table until you have called wait¹ for the child process or your program exits:
If a parent process terminates without waiting for all of its child processes to terminate, the remaining child processes will be assigned a new parent process ID corresponding to an implementation-dependent system process.
Of course you still can't spawn an unlimited amount of children, for more detail on that see Maximum number of children processes on Linux (as far as Linux is concerned, other OS will impose other limits).
¹: https://en.wikipedia.org/wiki/Zombie_process
I will try my best to explain.
First a bad example: where you fork() one child process, then wait for it to finish before forking another child process. This kills the multiprocessing degree, bad CPU utilization.
pid = fork();
if (pid == -1) { ... } // handle error
else if (pid == 0) {execv(...);} // child
else (pid > 0) {
wait(NULL); // parent
pid = fork();
if (pid == -1) { ... } // handle error
else if (pid == 0) {execv(...);} // child
else (pid > 0) {wait(NULL); } // parent
}
How should it be done ?
In this approach, you first create the two child process, then wait. Increase CPU utilization and multiprocessing degree.
pid1 = fork();
if (pid1 == -1) { ... } // handle error
if (pid1 == 0) {execv(...);}
pid2 = fork();
if (pid2 == -1) { ... } // handle error
if (pid2 == 0) {execv(...);}
if (pid1 > 0) {wait(NULL); }
if (pid2 > 0) {wait(NULL); }
NOTE:
even though it seems as parent is waiting before the second wait is executed, the child is still running and is not waiting to execv or being spawned.
In your case, you are doing the second approach, first fork all processes and save return value of fork then wait.
the parent can only wait() for one child at a time?
The parent can wait for all its children one at a time!, whether they already finished and became zombie process or still running. For more explained details look here.
How many child processes can a parent spawn before becoming infeasible?
It might be OS dependent, but one acceptable approach is to split the time given to a process to run in 2, half for child process and half for parent process.
So that processes don't exhaust the system and cheat by creating child processes which will run more than the OS wanted to give the parent process in first place.

Linux, waitpid, WNOHANG, child process, zombie

I running my program as daemon.
Father process only wait for child process, when it is dead unexpected, fork and wait again.
for (; 1;) {
if (fork() == 0) break;
int sig = 0;
for (; 1; usleep(10000)) {
pid_t wpid = waitpid(g->pid[1], &sig, WNOHANG);
if (wpid > 0) break;
if (wpid < 0) print("wait error: %s\n", strerror(errno));
}
}
But when child process being killed with -9 signal, the child process goes to zombie process.
waitpid should return the pid of child process immediately!
But waitpid got the pid number after about 90 seconds,
cube 28139 0.0 0.0 70576 900 ? Ss 04:24 0:07 ./daemon -d
cube 28140 9.3 0.0 0 0 ? Zl 04:24 106:19 [daemon] <defunct>
Here is the strace of the father
The father does not get stuck, wait4 was called always.
strace -p 28139
Process 28139 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0
nanosleep({0, 10000000}, NULL) = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0
About 90 seconds later father got the SIGCHILD and wait4 returned the pid of the dead child.
--- SIGCHLD (Child exited) # 0 (0) ---
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGKILL}], WNOHANG, NULL) = 28140
Why the child process does not exit immediately? On the contrary, it turns into zombie unexpectedly.
I finally find out there were some fd leaks during deep tracing by lsof.
After fd leaks were fixed, the problem was gone.
You could simply use
for (;;) {
pid_t wpid = waitpid(-1, &sig, 0);
if (wpid > 0) break;
if (wpid < 0) print("wait error: %s\n", strerror(errno));
}
instead of sleep for a while and try again.
It looks to me like waitpid is not returning the child pid immediately simply because that process is not available.
Furthermore, it looks like you actually want your code to do this because you specify waitpid() with the NOHANG option, which, prevents blocking, essentially allowing the parent to move on if the child pid is not available.
Maybe your process using something you didn't expect? Can you trace its activity to see if you find the bottleneck?
Here is a pretty useful link that might help you:
http://infohost.nmt.edu/~eweiss/222_book/222_book/0201433079/ch08lev1sec6.html

Execution when using fork in a program

I was reading about fork() when I tried out the following program. I could not understand the output of the following command but I could figure out what it does if I remove the second fork() call. Please explain me the flow of the following program.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main(int argc, char const *argv[])
{
pid_t pid;
int returnvalue;
pid = fork();
pid = fork();
if (!pid) cout<< "In the child"<<endl;
else cout<< "In parent"<<endl;
cout<< (&returnvalue)<<endl;
switch(pid)
{
case -1:
perror("fork");
return 0;
case 0:
cout<< "Child Process with pid: " <<getpid()<<endl;
cout<< "Parent's pid is: "<<getppid()<<endl;
cout<< "Exiting"<<endl;
returnvalue=2;
return returnvalue;
default:
cout<< "Parent process with pid: "<<getpid()<<endl;
cout<< "Child's pid: "<<pid<<endl;
cout<< "Waiting for child to exit"<<endl;
wait(&returnvalue);
cout<< "Child's exit status: "<<WEXITSTATUS(returnvalue)<<endl;
cout<< "Exiting!"<<endl;
}
return 0;
}
Why does it print "In parent" and "In the child" twice each?
Also, I read that every child process gets its own copy of variables. Shouldn't address of "returnvalue" be printed different?
Output:
In parent
0x7fff2d536428
Parent process with pid: 5487
Child's pid: 5489
Waiting for child to exit
In the child
0x7fff2d536428
Child Process with pid: 5489
Parent's pid is: 5487
Exiting
Child's exit status: 2
Exiting!
In parent
0x7fff2d536428
Parent process with pid: 5488
Child's pid: 5490
Waiting for child to exit
In the child
0x7fff2d536428
Child Process with pid: 5490
Parent's pid is: 5488
Exiting
Child's exit status: 2
Exiting!
Well you do have 2 calls to fork() will will result in 4 processes.
1st fork in P1 --> new process P2
2nd fork in P1 --> new process P3
2nd fork in P2 --> new process P4
the pid will be different based on the result following the 2nd fork() for sake of the explanation, I'll just say that P1 is the parent and remains the parent, P2 is a child of P1, but is a parent of P4, so its pid will be non zero, both P3 and P4 will have pid equal to 0. All 4 processes will enter the switch statement with a pid that will classify them as a parent or child, so since 2 have pid = 0 and 2 have pid != 0, 2 will be reported as parents and 2 will be reported as children.
P1 pid != 0 (classify parent)
P2 pid != 0 (classify parent)
P3 pid == 0 (classify child)
P4 pid == 0 (classify child)
It is true that P1 is created before P2 is created before P3 is created before P4, however when they enter into the switch statement and when they print out their messages is controlled by the scheduler. Consider the possibility that creating a process takes a lot of time (more then just printing stuff). So P1 creates P2 and then turns around and creates P3 meanwhile P2 is busy creating P4. P3 get created and prints stuff while P2 is still stuck creating P4.

Send TERM signal to child process spawned in another thread of parent process

I'm on Linux platform and using Perl. First of all I created a thread, and forked a child process in this new thread. When the parent in the new thread returned and joined to the main thread, I would like to send TERM signal to the child process spawned in the created thread, but the signal handler doesn't work, and the child process becomes zombie. Here's my code:
use strict;
use warnings;
use Thread 'async';
use POSIX;
my $thrd = async {
my $pid = fork();
if ($pid == 0) {
$SIG{TERM} = \&child_exit;
`echo $$ > 1`;
for (1..5) {
print "in child process: cycle $_\n";
sleep 2;
}
exit(0);
}
else {
$SIG{CHLD} = \&reaper;
}
};
$thrd->detach();
sleep 4;
my $cpid = `cat 1`;
kill "TERM", $cpid;
while (1) {}
sub child_exit {
print "child $$ exits!\n";
exit(0);
}
sub reaper {
my $pid;
while (($pid = waitpid(-1, &WNOHANG)) > 0) {
print "reaping child process $pid\n";
}
}
Any suggestions about how to successfully and safely send signal in this situation?
Why are you saying that the SIGTERM handler does not work? Because the child becomes a zombie?
All children process become zombies unless you wait for them. Put waitpid($pid, 0); after the kill(). Unless you see in child process: cycle 5 in your printout, the kill and the signal handler are working just fine.
Note that it's super shaky to use a hardcoded file to communicate between your forked process and your main process. I'd recommend you use a pipe.
Edit:
Wrt your sig handler not being called, I think this is a perl bug. perl sends signals only to the main thread. When you fork(), your thread becomes the main thread but I think perl does not realize that. You can work this around though by re-forwarding the signal to yourself.
Before you create the threads, just add:
sub sigforwarder {
threads->self()->kill(shift);
}
$SIG{TERM} = \&sigforwarder;
That should fix your problem
I think the problem is, that child_exit does not perform any exit on the parent thread. It just exits the child. I don't know exactly what's happening in perl (just stumbled upon a fork/exec-construction in c), but I would try to catch SIG_CHILD in the parent process to detect its termination.
(the message "child $$ exits" is output in the child's 1, so it will not be visible on screen, right?)
EDIT: I just tried your example and I think I got it: You are performing a fork in the child process and check for the pid to be 0 (which is the parent async-Process). You might just check for != 0.

Resources