The child that results from the second fork()
knows about the results of the first fork()
because it is an exact copy of the parent process.
You can work out what happens by drawing a little tree for yourself. Start with the first fork:
fork()
/\
/ \
parent --/ \-- child1
The parent gets back the PID of the child1
process, and child1
gets back 0. So we have something like:
PID(child1) && fork() || fork()
in the parent, and:
0 && fork() || fork()
in the child. Short circuiting means that the middle fork()
of the original expression doesn't get executed in the child, only in the parent. So now what happens to the tree?
fork()
/\
/ \
parent --/ \-- child1
fork()
/\
/ \
parent --/ \-- child2
parent
is the original process, and gets the PID of child2
. child2
, just like child1
, gets 0. What do our expressions look like now?
parent: PID(child1) && PID(child2) || fork() = 1 || fork()
child: 0 || fork()
child2: PID(child1) && 0 || fork() = 0 || fork()
Now, again by short-circuiting, parent
is done, and doesn't execute the last fork()
. Both child
and child2
have to, however. That leaves us with the following tree:
fork()
/\
/ \
parent --/ \-- child1
fork() fork()
/\ /\
/ \ / \
/ \ child1 --/ \-- child1-1
/ \
/ \
parent --/ \-- child2
fork()
/\
/ \
child2 --/ \-- child2-1
And that's it. child1
and child2
each get the PID of their respective children, and child1-1
and child2-1
each get back 0. Substituting those values in, the final expressions are:
parent: 1
child1: 0 || PID(child1-1) = 1
child2: 0 || PID(child2-1) = 1
child1-1: 0 || 0 = 0
child2-1: 0 || 0 = 0
And that's it - they all exit.