tags:

views:

376

answers:

1

Hi all,

I have a problem, I use pcntl_fork to fork a process in PHP,

$pid = pcntl_fork();
if ($pid == -1) {
 die('could not fork');
} else if ($pid) {
 // we are the parent
 pcntl_wait($status); //Protect against Zombie children
} else {
 pcntl_exec("/path/to/php/script");
 echo "Could not Execute...";
}

I am trying to figure out a way to monitor the status of the PHP script executed as the Child in the parent fork. Is there any way we can know if the child is still running or if there was any fatal errors raised during the execution of the child script and to catch all the messages from the child to parent process using;

pcntl_signal(SIGUSR1, "signal_handler");

Thanks & Regards,
Arun Shanker Prasad.

+4  A: 

You can definitely monitor the child process:

$pid = pcntl_fork();
if ($pid == -1) {
 die('could not fork');
} else if ($pid) {
 // we are the parent
 pcntl_waitpid($pid, $status, WUNTRACED); //Protect against Zombie children
 if (pcntl_wifexited($status)) {
   echo "Child exited normally";
 } else if (pcntl_wifstopped($status)) {
   echo "Signal: ", pcntl_wstopsig($status), " caused this child to stop.";
 } else if (pcntl_wifsignaled($status)) {
   echo "Signal: ",pcntl_wtermsig($status)," caused this child to exit with return code: ", pcntl_wexitstatus($status);
 }
} else {
 pcntl_exec("/path/to/php/script");
 echo "Could not Execute...";
}
  • pcntl_wifexited() - Checks if status code represents a normal exit
  • pcntl_wifstopped() - Checks whether the child process is currently stopped
  • pcntl_wifsignaled() - Checks whether the status code represents a termination due to a signal
  • pcntl_wexitstatus() - Returns the return code of a terminated child
  • pcntl_wtermsig() - Returns the signal which caused the child to terminate
  • pcntl_wstopsig() - Returns the signal which caused the child to stop

EDIT:

To clarify regarding messaging between parent and child process; you definitely cannot catch Exceptions across processes. As far as messaging, using only the PCNTL library you are also limited to process signals and exit codes.

Not knowing what, exactly, you are doing. You have a variety of other options. I'd suggest one of the following asynchronous messaging solutions, as they could possibly cover your needs.

File based

Your child processes could write messages to a file, which would be polled by the parent.

Memcache based

Same as above, but using memcached as the communications medium.

Database based

Same as above, but using a db table as the communications medium.

PHP's semaphore/IPC library

http://us3.php.net/manual/en/book.sem.php

This allows you to use methods like msg_send() and msg_receive() to communicate across processes.

I'm confident one of these will provide the solution you are looking for. Going into the specifics of how to use any of these methods, is probably beyond the scope of this question though, but feel free to ask a new question if you need help with whichever method you choose to utilize.

hobodave
Thanks hobodave, pcntl_wstopsig seems to be good :) I was thinking more along the lines of catching the exception thrown from the Child? And a major part of the question involves around how to send messages to the parent from the Child? Can the signals be used reliably to get messages from the child?
Arun Shanker Prasad
Arun, see my updated answer above.
hobodave
Thanks very much hobodave. I tried to communicate from the child to the parent using signals, but my problem was that the communication was not reliable, there were some instances when the signal did not get handled at all.. Is that to be expected or is there something that might be wrong in my code? The DB option is a no go as I am doing this for a large scale process. Will look at the file option.
Arun Shanker Prasad
Without seeing your code I can't really tell you what the problem may have been. Make sure you are using the WUNTRACED constant in your pcntl_waitpid(). Please note that using the file is probably the **worst** method of the ones I suggested, especially if this is a "large scale process" as you claim. There will be high contention for the file handle by all the processes, you will run into blocking issues and other headaches. I would rule this option out for all but the simplest of scripts. Please accept my answer as I feel I have adequately answered your questions.
hobodave
Thanks hobodave for your reply. I was actually using WNOHANG since I will be logging the status if the current child then move on to the next until all the children were exited. I was not able to get the status when the child PHP script exited unexpectedly, like when an exception was raised. Any suggestions to get around this?
Arun Shanker Prasad
You have to OR the constants together: pcntl_waitpid($pid, $status, WNOHANG | WUNTRACED);
hobodave
Thanks hobodave for your reply. I had OR'ed the two together, this would catch all the signals in the signal handler but this still does not solve my problem "I was not able to get the status when the child PHP script exited unexpectedly, like when an exception was raised." When WNOHANG | WUNTRACED the "pcntl_wstopsig" always returns a "0".
Arun Shanker Prasad