PHP pcntl_signal callbacks not called

This is full reproducible code.

<?php class console{ public static function log($msg, $arr=array()){ $str = vsprintf($msg, $arr); fprintf(STDERR, "$str\n"); } } function cleanup(){ echo "cleaning up\n"; } function signal_handler($signo){ console::log("Caught a signal %d", array($signo)); switch ($signo) { case SIGTERM: // handle shutdown tasks cleanup(); break; case SIGHUP: // handle restart tasks cleanup(); break; default: fprintf(STDERR, "Unknown signal ". $signo); } } if(version_compare(PHP_VERSION, "5.3.0", '<')){ // tick use required as of PHP 4.3.0 declare(ticks = 1); } pcntl_signal(SIGTERM, "signal_handler"); pcntl_signal(SIGHUP, "signal_handler"); if(version_compare(PHP_VERSION, "5.3.0", '>=')){ pcntl_signal_dispatch(); console::log("Signal dispatched"); } echo "Running an infinite loop\n"; while(true){ sleep(1); echo date(DATE_ATOM). "\n"; } 

When I run this, I see the date values ​​every second. Now, if I press Ctrl + C cleanup , the function is not called. Actually signal_handler not called.

Here is an example output.

 $ php testsignal.php Signal dispatched Running an infinite loop 2012-10-04T13:54:22+06:00 2012-10-04T13:54:23+06:00 2012-10-04T13:54:24+06:00 2012-10-04T13:54:25+06:00 2012-10-04T13:54:26+06:00 2012-10-04T13:54:27+06:00 ^C 
+4
source share
3 answers

CTRL+C starts SIGINT , for which you did not set a handler for:

 <?php ... function signal_handler($signo){ ... case SIGINT: // handle restart tasks cleanup(); break; ... } ... pcntl_signal(SIGINT, "signal_handler"); ... 

Now it works:

 $ php testsignal.php Signal dispatched Running an infinite loop 2012-10-08T09:57:51+02:00 2012-10-08T09:57:52+02:00 ^CCaught a signal 2 cleaning up 2012-10-08T09:57:52+02:00 2012-10-08T09:57:53+02:00 ^\Quit 
+8
source

It is important to understand how declare works: http://www.php.net/manual/en/control-structures.declare.php

he needs to either wrap up what ever it can be declared in the "root" script (index.php or something like that).

funny fact; IF check around declare(ticks = 1); it doesn’t matter if you delete these 3 lines, the script will stop working, if you change the check to if (false) , it will work, the ad will be evaluated outside the normal code stream xD

+4
source

After correcting Ruben de Vries for using declaring ticks during compilation, there are two things in the source code (except for the lack of an INT signal).

As Ruben says:

 if(false) declare(ticks=1); 

This means that ticks will be processed. Give it a try! The docs say how you cannot use variables, etc. This is compilation time.

In addition, using pcntl_signal_dispatch() not a direct substitute for declaring ticks — it must be called at runtime — for example, ticks are executed automatically. Thus, calling it once in the head of the script seems to process any signals awaiting consideration at this point.

For pcntl_signal_dispatch () to work like using ticks to drive it, you will need to sprinkle it all over your code ... depending on where / when you want the interrupts to take effect.

At least:

 while(true){ sleep(1); echo date(DATE_ATOM). "\n"; pcntl_signal_dispatch(); } 

Thus, the source code actually uses ticks for all versions of PHP and additionally checks only one signal received at boot time if the version is greater than 5.3. Not what the OP intended.

Personally, I think that using ticks to control PCNTL signals a huge dirty pain. The "loop" in my case is in third-party code, so I can’t add a submit method, and declaring ticks at the top level doesn’t work in production unless I add it to every file (some autoload, scope or PHP7 version I think a specific problem )

0
source

Source: https://habr.com/ru/post/1437744/


All Articles