Improving mod_perl Driven Site's Performance -- Part VI: Forking and Executing Subprocesses from mod_perl Page 4
The simplest solution is to ignore your dead children. Just add this
line before the fork() call:
{CHLD} = 'IGNORE';When you set the
CHLD(SIGCHLDin C) signal handler to'IGNORE', all the processes will be collected by theinitprocess and are therefore prevented from becoming zombies. This doesn't work everywhere, however. It proved to work at least on Linux OS.Note that you cannot localize this setting with
local(). If you do, it won't have the desired effect.So now the code would look like this:
my = shift; ->send_http_header('text/plain');{CHLD} = 'IGNORE';defined (my = fork) or die "Cannot fork: \n"; if () { print "Parent has finished\n"; } else { # do something time-consuming CORE::exit(0); }Note that
waitpid()call has gone. The {CHLD} = 'IGNORE'; statement protects us from zombies, as explained above.Another, more portable, but slightly more expensive solution is to use a double fork approach.
my = shift; ->send_http_header('text/plain');defined (my = fork) or die "Cannot fork: \n"; if () { waitpid(,0); } else { defined (my = fork) or die "Kid cannot fork: \n"; if () { CORE::exit(0); } else { # code here # do something long lasting CORE::exit(0); } }Grandkid becomes a ''child of init'', i.e. the child of the process whose PID is 1.
Note that the previous two solutions do allow you to know the exit status of the process, but in my example I didn't care about it.
Another solution is to use a different SIGCHLD handler:
use POSIX 'WNOHANG'; {CHLD} = sub { while( waitpid(-1,WNOHANG)>0 ) {} };Which is useful when you
fork()more than one process. The handler could callwait()as well, but for a variety of reasons involving the handling of stopped processes and the rare event in which two children exit at nearly the same moment, the best technique is to callwaitpid()in a tight loop with a first argument of-1and a second argument ofWNOHANG. Together these arguments tellwaitpid()to reap the next child that's available, and prevent the call from blocking if there happens to be no child ready for reaping. The handler will loop untilwaitpid()returns a negative number or zero, indicating that no more reapable children remain.While you test and debug your code that uses one of the above examples, You might want to write some debug information to the error_log file so you know what happens.
Read perlipc manpage for more information about signal handlers.
A Complete Fork Example
Now let's put all the bits of code together and show a well written fork code that solves all the problems discussed so far. I will use an <Apache::Registry> script for this purpose:
