5

Ok, so I've been trying to get Process Signals to work with PHP scripts. I've run into a lot of stuff where I am just not sure what is going on, and I feel like the documentation doesn't do a very good job of explaining it.

So let's say I follow the example on registering signals:

<?php
// tick use required as of PHP 4.3.0
declare(ticks = 1);

// signal handler function
function sig_handler($signo)
{

     switch ($signo) {
         case SIGTERM:
             // handle shutdown tasks
             exit;
             break;
         case SIGHUP:
             // handle restart tasks
             break;
         case SIGUSR1:
             echo "Caught SIGUSR1...\n";
             break;
         default:
             // handle all other signals
     }

}

echo "Installing signal handler...\n";

// setup signal handlers
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP,  "sig_handler");
pcntl_signal(SIGUSR1, "sig_handler");

// or use an object, available as of PHP 4.3.0
// pcntl_signal(SIGUSR1, array($obj, "do_something"));

echo"Generating signal SIGTERM to self...\n";

// send SIGUSR1 to current process id
posix_kill(posix_getpid(), SIGUSR1);

echo "Done\n";

?>

However, within my sig_handler function, I add an exit(1) at the end. Will the echo "Done\n"; still be executed? I have attempted something similar, albeit in a class structure, and it was- only before my sig_handler ever got called.

My class __construct calls the function registerSignals:

private function registerSignals(){
    if(function_exists("pcntl_signal")){
        //call_user_func([$this, "sigintCleanup"]);
        pcntl_signal(SIGINT, [$this, "sigintCleanup"]);
        pcntl_signal(SIGTERM, [$this, "sigtermCleanup"]);
        pcntl_signal(SIGHUP, [$this, "sighupCleanup"]);
        pcntl_signal(SIGUSR1, [$this, "sigusr1Cleanup"]);
    }
}

protected function sigintCleanup(){
    echo "In SIGINT cleanup\n";
    $this->cleanup();
}

protected function sigtermCleanup(){
    echo "In SIGTERM cleanup\n";
    $this->cleanup();
}

protected function sighupCleanup(){
    echo "In SIGHUP cleanup\n";
    $this->cleanup();
}

protected function sigusr1Cleanup(){
    echo "In SIGUSR1 cleanup\n";
    $this->cleanup();
}

protected function cleanup(){
    echo "Shutting down\n";
    exit(1);
}

And then within my testing of this process, I do some simple sleeps and echos (start is just a function called after the construction and signal registration is finished):

function start(){
    echo "-- Testing the test script --\n";
    sleep(10000);
    echo "given how ticks work, this might not be called...\n";
    echo "\nAfter sleep... this should not be executed if there was a signal interrupt.\n";
}

So I use ctl-c during the sleep. My result?

-- Testing the test script --
^Cgiven how ticks work, this might not be called...

After sleep... this should not be executed if there was a signal interrupt.
In SIGINT cleanup
Shutting down

As you can see from my echos, I kinda figured maybe the way ticks work was responsible for finishing the start function before handling the signal. I still think this might be the case. The truth is, I just don't know.

I do declare ticks at the top of my program:

declare(ticks = 1);

Not handling signals immediately is causing problems for me. What if, for instance, I had this bit of code in my start function (and I've tested this)?

$count = 0;
while(true){
    count++;
    echo "count\n";
    sleep(5);
}

Even if my cleanup function has an exit, I never reach that because the SIGINT just knocks me out of sleep, and I continue in the loop and begin sleeping again.

So here's my question: How does signal handling work in PHP? How can I guarantee that when I get a signal, it is handled immediately? I don't just want some piece of code that will fix this, I would like an explanation (or at least a link to a good one and a summary).

PHP version: 5.4.22

OS: Ubuntu 12.10

Sam
  • 7,252
  • 16
  • 46
  • 65
MirroredFate
  • 12,396
  • 14
  • 68
  • 100
  • I tried quite hard to reproduce your problem, and the only way I managed to see your problem is by setting `ticks` to a value greater than 1. What is your PHP version? OS? Please post your PHP's "Configure Command", as well as a full working code sample that exhibits the unexpected behaviour. – RandomSeed Apr 19 '14 at 02:47

1 Answers1

0

sleep() will be knocks out by some signal, and it will return left sleep seconds, you can do something like this to keep it sleep.

.....
declare(ticks = 1);

$left = sleep(1000)
while ($left > 0) {
   $left = sleep($left);
}
joan16v
  • 5,055
  • 4
  • 49
  • 49