Subsequent pcntl_signal signals do not start the handler

Lemme begins by describing the basic description of the code that I have. I start with the main parent process (NOTE: I do not show all the functions for simplicity. Let me know if you need me to expand at any time):

declare(ticks=1); pcntl_signal(SIGHUP, array('forker', 'restartSignalHandler')); if(forker_is_not_running()){ new Forker(); } class Forker { private $active_forks = array(); private $parent_pid = null; public function __construct(){ $this->parent_pid = getmypid(); $this->create_fork(); $this->wait_for_active(); } public function wait_for_active(){ while(!empty($this->active_forks)){ foreach($this->active_forks as $k=>$fork){ if($this->fork_no_longer_running($fork)){ unset($this->active_forks[$k]); } } } } // Pseudo code public function fork_no_longer_running($pid){ // return true if 'ps -elf | grep $pid' doesn't returns only the grep command // else return false (aka the fork is still running) } public function create_fork(){ $pid = pcntl_fork(); if($pid == -1){ posix_kill($this->parent_pid, SIGTERM); } else if($pid){ // add the pid to the current fork $this->active_forks[] = $pid; } else { // Run our process pcntl_exec('/usr/bin/php', array('/domain/dev/www/index.php','holder','process')); exit(0); } } public function restartSignalHandler(){ $forks = $this->active_forks; foreach($forks as $pid){ $this->create_fork(); posix_kill($pid, SIGINT); } } } class holder { public function process(){ $x = new Processor(); } } class Processor { public function __construct(){ pcntl_signal(SIGINT, array($this, "shutdownSignalHandler")); } public function shutdownSignalHandler(){ echo "Shutting down"; exit; } } 

Here's what happens:

  • I run my script and correctly get processes (e.g. Parentpid: 2, childpid: 3)
  • Then I send the parent signal SIGHUP and it correctly kills and starts a new child process (e.g. Parentpid: 2, childpid: 4)
  • Then I send the second signal SIGHUP to the parent signal, and it tries correctly and adds a new child process, but it refuses to kill the second childpid. (e.g. Parentpid: 2, undyingchildpid: 4, newchildpid: 5)

Lemme knows if this requires more details / does not make sense. I can’t understand why the first time he will kill children correctly, but the second time it’s not.

The even part of WEIRDER is that when I change it so that I change my reboot handler so that it continues to try to kill the child with SIGINT, it fails every time, but when I send it the SIGKILL command, it kills the child process:

 if($time_passed > 60){ posix_kill($pid, SIGKILL); } 

I need a child so that it can be killed by SIGINT in order to properly handle it. I don't want just SIGKILL. Is there a reason why the 2nd time around SIGINT will not work, but SIGKILL will?

+8
php subprocess kill-process fork pcntl
source share
1 answer

First of all, you do not need to branch. Your code executes exec inside the child, you can just run exec without forking, and the OS will spawn your command as a child. If you want to use fork, just include file in the child, not exec.

 public function create_fork(){ //no need to actually fork! pcntl_exec('/usr/bin/php', array('/domain/dev/www/index.php','holder','process')); } //if you want to fork, better do it like this : public function create_fork(){ $pid = pcntl_fork(); if($pid == -1){ posix_kill($this->parent_pid, SIGTERM); } else if($pid){ // add the pid to the current fork $this->active_forks[] = $pid; } else { // Run our process include '/domain/dev/www/index.php'; SomeClass::someMethod(); exit(0); } } 

Also, when using fork, you need waitpid for children. So, in your code you need to insert something like:

 //somewhere in a loop : $pidOfExittedChild = pcntl_waitpid (-1, $status, WNOHANG); if ($pidOfExittedChild) { //a child has exitted, check its $status and do something } 

More details: http://php.net/manual/en/function.pcntl-waitpid.php

+1
source share

All Articles