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 overriden by 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::Registry or 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.

Freeing the Parent Process

In the child code you must also close all the pipes to the connection socket that were opened by the parent process (i.e. STDIN and 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 STDIN and/or STDOUT streams you should re-open them. You may need to close or re-open the STDERR filehandle. 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 port 8000

Apache::SubProcess comes to help and provides a method cleanup_for_exec() which takes care of closing this file descriptor.

This article was originally published on Feb 27, 2001

Thanks for your registration, follow us on our social networks to keep up-to-date