2
votes

I'm having problems with killing parent process that have 1 child - parent is waiting for child to exit and only after that kill handler is called. When the kill handler is not installed (pcntl_signal(SIGTERM, "kill_handler")) script terminates immediately.

I need that after submitting kill command to terminate parent process the signal will be immediately received by kill handling function. This function then will kill the child process .

Any ideas?

1

1 Answers

2
votes

If you are capturing a signal, you'll have to check them sometime. If you are hanging in a blocking waitpid(), use declare(ticks=1); at the top of your scripts, or use a WNOHANG in a loop (possiblye sleeping), and call pcntl_signal_dispatch().

This does not work:

<?php
pcntl_signal(SIGTERM, 'kill_handler');
function kill_handler($no){
        global $pid;
        posix_kill($pid,SIGTERM);
        echo 'Done killing '.$pid.PHP_EOL;
        exit;
}
$pid = pcntl_fork();
if ($pid) {
        echo 'Forked, parent is'.posix_getpid().PHP_EOL;
        pcntl_waitpid($pid,$status);
} else {
        echo 'child '.posix_getpid().PHP_EOL;
        $i = 0;
        while($i++ < 30){
                echo date('H:i:s').PHP_EOL;
                sleep(1);
        }
        echo 'done'.PHP_EOL;
}
?>

This would work for both parent & child:

<?php
declare(ticks=1);
//rest of previous code
?>

Without ticks, this would let the parent die on a SIGTERM, but because there is no signal dispatch in the child the child continues:

<?php
pcntl_signal(SIGTERM, 'kill_handler');
function kill_handler($no){
        global $pid;
        posix_kill($pid,SIGTERM);
        echo 'Done killing '.$pid.PHP_EOL;
        exit;
}
$pid = pcntl_fork();
if ($pid) {
        echo 'Forked, parent is'.posix_getpid().PHP_EOL;
        while(0==pcntl_waitpid($pid,$status,WNOHANG)){
                echo "nothing yet".PHP_EOL;
                pcntl_signal_dispatch();
                sleep(1);
        }
} else {
        echo 'child '.posix_getpid().PHP_EOL;
        $i = 0;
        while($i++ < 30){
                echo date('H:i:s').PHP_EOL;
                sleep(1);
        }
        echo 'done'.PHP_EOL;
}
?>

So either you'll have to call pcntl_signal_dispatch() in the child itself, or you'll have to call pcntl_signal only after forking.