Understanding fork() - linux

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.

Related

C Programming Fork Example

How many processes are created when running the following program ? I can not solve. I would appreciate if you help
int main()
{
int i;
for (i=fork(); i<2; i++ )
fork();
}
fork() creates a child process, creating an another instance of the parent process. It returns 0 to the child and PID of the child to the parent.
In this case, when i = fork() is executed,
The parent gets i assigned as the PID of the child process, which is most likely greater than 1. The for loop in the parent will run not run even once as i < 2 will fail. At this point of time there are two processes P and C1 (Child)
After the fork is executed by parent, child gets a 0 as return value, i = 0. This means the condition i < 2 is successful. Child executes the fork() in the loop body, creating C2. Value of i in both C1 and C2 are 0. i gets incremented to 1.
C1 and C2 execute i < 2, This condition is successful. Fork is executed by both. C3 is spawned off by C1 and C4 by C2.
i's value gets incremented to 2. i < 2 fails. All of them get out of the loop
To summarise, there are 4 child processes created in this program. You can try this with the following program where you will see 5 PIDs getting printed.
#include <stdio.h>
main()
{
int i = 0;
for (i = fork(); i < 2; i++)
fork();
printf("Hello World i %d\n", getpid());
}

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.

Process wait using linux system call wait

I am trying to create a process using fork system call and then wait on the child process. I have used the following:
waitpid (pid, &status, 0);
1) The first problem is that the status is 8 bit shifted to the left e.g., if the child process returns 1, the waitpid function returns the value of the status in the status variable to be 256. Please let me know why it is doing that.
2) According to the manual, the waitpid waits for the child process to change state. but then it also says:
"The wait() system call suspends execution of the calling process until
one of its children terminates. The call wait(&status) is equivalent
to:
waitpid(-1, &status, 0);"
I am a bit confused here whether the waitpid and the wait calls wait for state change or for child process termination. Kindly clearify this point.
What does the zero in the third arguement specifies?
3) If i put the child process in sleep state, doesn't the state of the child process changes to be in waiting state by waiting for e.g., 5 secs?
Following is my program:
int main(int argc, char ** argv)
{
pid_t pid = fork();
pid_t ppp;
if (pid==0)
{
sleep(8);
printf ("\n I am the first child and my id is %d \n", getpid());
printf ("The first child process is now exiting now exiting\n\n");
exit (1);
}
else {
int status = 13;
printf ("\nI am now waiting for the child process %d\n", pid);
waitpid (pid, &status, 0);
printf ("\n the status returned by the exiting child is %d\n", status>>8);
}
printf("\nI am now exiting");
exit(0);
}
Thanks
The status parameter encodes more than just the exit code of the child. From man waitpid:
WIFEXITED(status)
returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should only be employed if WIFEXITED returned true.
main waitpid explains what the third parameter does.
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 (but not traced via ptrace(2)). Status for traced children which have stopped is provided even if this option is not specified.
WCONTINUED (since Linux 2.6.10)
also return if a stopped child has been resumed by delivery of SIGCONT.
State change is very precisely and narrowly defined. From man waitpid:
A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal.
Going to sleep is not a state change. Being stopped by SIGSTOP/SIGTSTP is.

How does wait() work in 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.

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

Resources