Improving mod_perl Driven Site's Performance -- Part VI: Forking and Executing Subprocesses from mod_perl Page 2
When the process is successfully forked -- the parent receives the PID
of the newly spawned child as a returned value of the
fork() call and
the child receives 0. Now the program splits into two. In the above
example, the code inside the first block after if will be executed
by the parent and the code inside the first block after else will
be executed by the child process.
It's important not to forget to explicitly call
exit() at the end of
the child code when forking. Since if you don't and there is some code
outside the if/else block, the child process will execute it as
well. But under mod_perl there is another nuance -- you must use
CORE::exit() and not
exit(), which would be automatically
Apache::exit() if used in conjunction with
Apache::Registry and similar modules. And we want the spawned
process to quit when its work is done, otherwise it'll just stay alive
using resources and doing nothing.
The parent process usually completes its execution path and enters the
pool of free servers to wait for a new assignment. If the execution
path is to be aborted earlier for some reason one should use
Apache::exit() or die(). In the case of
Apache::PerlRun handlers a simple
exit() will do the right thing.
The child shares with its parent its memory pages until it has to modify
some of them, which triggers a copy-on-write process which copies
these pages to the child's domain before the child is allowed to
modify them. But this all happens afterwards. At the moment the
fork() call executed, the only work to be done before the child
process goes on its separate way is setting up the page tables for the
virtual memory, which imposes almost no delay at all.
In the child code you must also close all the pipes to the connection
socket that were opened by the parent process (i.e.
STDOUT) and inherited by the child, so the parent will be able to
complete the request and free itself for serving other requests. If
you need the
STDOUT streams you should re-open
them. You may need to close or re-open the
It's opened to append to the error_log file as inherited from its
parent, so chances are that you will want to leave it untouched.
Under mod_perl, the spawned process also inherits the file descriptor that's tied to the socket through which all the communications between the server and the client happen. Therefore we need to free this stream in the forked process. If we don't do that, the server cannot be restarted while the spawned process is still running. If an attempt is made to restart the server you will get the following error:
[Mon Dec 11 19:04:13 2000] [crit] (98)Address already in use: make_sock: could not bind to address 127.0.0.1 port 8000
Apache::SubProcesscomes to help and provides a method
cleanup_for_exec()which takes care of closing this file descriptor.