if doesn't just check for fork returning undef; it also checks for returning 0, which is what fork does in the child. From the manual:
(fork) returns ... 0 to the child process,
So this code is creating three processes:
- Parent: first fork returns nonzero $pid, parent executes waitpid($pid). This returns very quickly, since the child exits almost immediately (though not the grandchild).
- Child: First fork returns zero in child, second fork returns PID of grandchild, child exits.
- Grandchild: First fork returns zero in child, second fork returns zero in grandchild, grandchild either exec's or die's.
When the grandchild finishes, its parent is already gone, so it's been reparented to init, which notices its death and waits for it, avoiding a zombie.
The OP's problem is that he's waiting for the child but running the long-running process in the grandchild. The fix is to eliminate the second fork, and just do the work in the child; the purpose of a second fork is to do something in the background without having to wait for it, which is what the OP is trying to avoid.
Here's a small example:
Here's a version which does what I believe the OP wants.
warn "PID $$ (parent) forking\n";
unless ($pid = fork) {
warn " PID $$ (child) exec'ing\n";
exec "sleep 5";
die "Couldn't run getSite.pl";
}
warn "PID $$ (parent) executing waitpid\n";
waitpid($pid,0);
warn "PID $$ (parent) done.\n";
But, this is completely equivalent to system, so why not just use that?
| [reply] [d/l] [select] |
Every fork in the code is preceded by unless. unless (fork evaluating to undef()) is the only way any of the six branches can be followed and the only other possibility (pid=0) can't happen - it appears from your response you have projected your own ideas of intent and have lost the actual flow in that respect.
| [reply] |
| [reply] [d/l] [select] |