Question

According to the PHP docs for pcntl_wait,

The wait function suspends execution of the current process until a child has exited, or until a signal is delivered whose action is to terminate the current process or to call a signal handling function.

However, when I run the following code and send SIGTERM to the parent process with kill -s SIGTERM [pid] the signal handler is only called after the child exits (i.e. I have to wait for the sleep to finish. Shouldn't pcntl_wait() be interrupted by SIGTERM?

fork_test.php:

<?php
  declare(ticks = 1);

  function sig_handler($signo) {
    switch ($signo) {
      case SIGTERM:
        echo 'SIGTERM' . PHP_EOL;
        break;
      default:
    }
  }

  pcntl_signal(SIGTERM, 'sig_handler');

  $pid = pcntl_fork();

  if ($pid == -1) {
     die('could not fork');
  }
  else if ($pid) {
    echo 'parent' . PHP_EOL;

    pcntl_wait($status);
  }
  else {
    echo 'child' . PHP_EOL;
    sleep(30);
  }
?>

Output (SIGTERM only appears after waiting 30 seconds):

$ php fork_test.php
child
parent
SIGTERM

PHP Version => 5.3.3

Was it helpful?

Solution

Your call to pcntl_signal specifies that the call should be restarted. Check the docs, restart_syscalls is true by default. So your call to pcntl_signal doesn't return until the child has terminated.

You have no call to flush. So PHP can hold the output of echo in a buffer.

So the behavior you are seeing is precisely the behavior you are requesting. The system call is restarted and the output is buffered.

OTHER TIPS

pcntl_wait call cannot be interrupted by signals unless restart_syscalls=false OR a child dies.

From the documentation of wait syscall (which is what pcntl_wait calls) :

... they block until either a child changes state or a signal handler interrupts the call (assuming that system calls are not automatically restarted using the SA_RESTART flag of sigaction(2)).

The last part is very important. The call will be interrupted only if the system calls are not automatically restarted (restart_syscalls=false).

Interestingly, not all syscall behave the same when a process receives a signal. For example, sleep syscall will either wait the amount of seconds OR wait for any signal before continuing. sleep won't be restarted where it was interupted even if you pass restart_syscalls=true. From the sleep manual :

sleep() causes the calling thread to sleep either until the number of real-time seconds specified in seconds have elapsed or until a signal arrives which is not ignored.

TL;DR; pcntl_wait cannot be interrupted unless you pass restart_syscalls=false.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top