in reply to Re^2: Waiting for an External Program to Finish Executing
in thread Waiting for an External Program to Finish Executing

If you look at the manual, you'll see that fork either returns the pid (and spawns a child) or undef if the fork was unsuccessful causing the code after the unless to finally execute, i.e. whenever the system is being sufficiently thrashed to get an undef() back from fork. Note also the conditions under which the manual states that zombies will be accumulated. The OP code meets the criteria for a zombie factory of von Neumann proportions. In fact the intended functionality only gets executed whenever there is a spawn error and sufficient spawn errors are generated to cause "unless" to function precisely because this code is thrashing the machine enough to cause such errors in turn enough to cause the branches with execs to be executed approximately in parallel, because the spawn error cirmsumstances will occur simultaneously of course. Furthermore, the OPs actual symptoms are explained by this analysis but conflict with yours.

-M

Free your mind

Replies are listed 'Best First'.
Re^4: Waiting for an External Program to Finish Executing
by sgifford (Prior) on Nov 14, 2005 at 17:23 UTC
    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?

      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.

      -M

      Free your mind

        Why do you think that $pid == 0 "can't happen", when it's plainly documented that fork returns 0 in the child every single time it is executed? Have you actually called fork and observed its return values in parent and child to verify your assertion? If you don't think it returns 0 in the child, what do you think it returns, and how do you think the two processes know which is which?

        How do you think my sample code "(loses) the actual flow" when it's copied and pasted from the OP's, with minimal changes to have it output its flow?