PHP forking and multiple child signals PHP forking and multiple child signals php php

PHP forking and multiple child signals


One way is to keep an array of the PIDs of the child processes, and in the signal handler check each PID to see if it's still running. The (untested) code would look like:

declare(ticks = 1);$openProcesses = 0; $procs = array();$max = 3;pcntl_signal(SIGCHLD, "childFinished");while (!time_is_up()) {    if (there_is_something_to_do()) {        $pid = pcntl_fork();        if (!$pid) {                  foo();                    exit(0);              } else {                      $procs[] = $pid; // add the PID to the list            ++$openProcesses;            if ($openProcesses >= $max) {                pcntl_wait($status);                 }                                   }    } else {        sleep(3);    }}function childFinished($signo) {    global $openProcesses, $procs;    // Check each process to see if it's still running    // If not, remove it and decrement the count    foreach ($procs as $key => $pid) if (posix_getpgid($pid) === false) {        unset($procs[$key]);        $openProcesses--;    }}


You could have children send a SIGUSR1 to the parent when they start,then a SIGUSR2 before they exit. The other thing you are dealing with when using primitive signals is the kernel merging them, which it does not do with RT signals. In theory, ANY non-rt signal could be merged.

You might implement some kind of simple locking using sqlite, where only one child at a time can have the talking stick. Just make sure that children handle normally fatal signals so that they remain alive to free the lock.


I know this is about 8 years too late (and I hope you found an answer), but just in case it helps someone else I am going to answer.

The use of the pcntl_w* functions will be your friend here and you will probably want to implement a process reaper. The documentation is not very helpful and still does not contain any useful examples.

This would be a multi-part process:

1 - use pcntl_signal send trapped signals to your signal handler

2 - Do your looping/polling and within that loop;

3 - Iterate through the array of your children (which you will create below) and reap them as necessary

4 - fork(): This will consist of the following:

pcntl_async_signals(true);$children = array();while ($looping === true){    reapChildren();    if (($pid = pcntl_fork()) exit (1); // error    elseif ($pid) // parent    {         $children[] = $pid;        // close files/sockets/etc        posix_setpgid ($pid,posix_getpgrp());    }    else    { // child        posix_setpgid(posix_getpid(),posix_getppid());        // ... jump to child function/object/code/etc ...        exit (0); // or whatever code you want to return    }} // end of loop

In the reaper, you will need the following:

function reapChildren(){    global $children;    foreach ($children as $idx => $pid)    {        $rUsage = array();        $status = 0; // integer which will be used as the $status pointer        $ret = pcntl_waitpid($pid, $status, WNOHANG|WUNTRACED, $rUsage);        if (pcntl_wifexited($status)) // the child exited normally        {            $exitCode = pcntl_wexitstatus($status); // returns the child exit status        }        if (pcntl_wifsignaled($status))  // the child received a signal        {            $signal = pcntl_wtermsig($status); // returns the signal that abended the child        }        if (pcntl_wifstopped($status))        {            $signal = pcntl_wstopsig($status); // returns the signal that  stopped the child        }    }}

The above reaper code will allow you to poll the status of your children and if you are using php7+, the $signalInfo array which is filled in at your signal handler will contain a lot of useful information you can use.. var_dump it.. check it out. Also, using pcntl_async_signals(true) in php7+ replaces the need for declare(ticks=1) and manually calling pcntl_signal_dispatch();

I hope this helps.