PHP: pcntl_signal - Manual

downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

pcntl_wait pcntl_setpriority

Last updated: Sat, 27 Jan 2007

view this page in

# pcntl_signal

(PHP 4 >= 4.1.0, PHP 5)

pcntl_signal -- Installs a signal handler

## Description

bool pcntl_signal ( int signo, callback handle [, bool restart_syscalls] )

The pcntl_signal() function installs a new signal handler for the signal indicated by `signo`. The signal handler is set to `handler` which may be the name of a user created function, or either of the two global constants SIG_IGN or SIG_DFL. The optional `restart_syscalls` specifies whether system call restarting should be used when this signal arrives and defaults to `TRUE`.

Возвращает `TRUE` в случае успешного завершения или `FALSE` в случае возникновения ошибки.

> Замечание: The optional `restart_syscalls` parameter became available in PHP 4.3.0.

> Замечание: The ability to use an object method as a callback became available in PHP 4.3.0. Note that when you set a handler to an object method, that object's reference count is increased which makes it persist until you either change the handler to something else, or your script ends.

Пример 1. pcntl_signal() example

`<?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"
?>`

> Замечание: As of PHP 4.3.0 PCNTL uses ticks as the signal handle callback mechanism, which is much faster than the previous mechanism. This change follows the same semantics as using "user ticks". You must use the declare() statement to specify the locations in your program where callbacks are allowed to occur for the signal handler to function properly (as used in the above example).

See also pcntl_fork() and pcntl_waitpid().

add a note User Contributed Notes
pcntl_signal
rob at robertjohnkaper dot com
16-Nov-2006 03:00
`Tip: when using objects, don't set the signal handler from the constructor or even a method called from the constructor - your internal variables will be uninitialised.`
nate at example dot com
29-Oct-2006 04:10
`If you have a script that needs certain sections to not be interrupted by a signal (especially SIGTERM or SIGINT), but want to make your script ready to process that signal ASAP, there's only one way to do it. Flag the script as having received the signal, and wait for your script to say its ready to process it.
Here's a sample script:
<?
$allow_exit = true; // are we permitting exit?
$force_exit = false; // do we need to exit?
declare(ticks = 1);
register_tick_function('check_exit');
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
function sig_handler () {
global $allow_exit, $force_exit;
if ($allow_exit)
exit;
else
$force_exit = true;
}
function check_exit () {
global $allow_exit, $force_exit;
if ($force_exit && $allow_exit)
exit;
}
$allow_exit = false;
$i = 0;
while (++$i) {
echo "still going (${i})\n";
if ($i == 10)
$allow_exit = true;
sleep(2);
}
?>
You set $allow_exit to true at all times when it is perfectly acceptable that your script could exit without warning. In sections where you really need the script to continue running, you set $allow_exit to false. Any signals received while $allow_exit is false will not take effect until you set $allow_exit to true.
<?
$allow_exit = true;
// unimportant stuff here. exiting will not harm anything
$allow_exit = false;
// really important stuff not to be interrupted
$allow_exit = true;
// more unimportant stuff. if signal was received during
// important processing above, script will exit here
?>`
imslushie at hotmaildotcom dot com
04-Oct-2006 07:16
`I have been having trouble reaping my child process. It seemed most of the time, children were reaped properly but *sometimes* they would stay as zombies. I was catching the CHLD signal to reap child processes with the following code:
<?php
function childFinished($signal)
{
global $kids;
$kids--;
pcntl_waitpid(-1, $status);
}
$kids = 0;
pcntl_signal(SIGCHLD, "childFinished");
for ($i = 0; $i < 1000; $i++)
{
while ($kids >= 50) sleep(1);
$pid = pcntl_fork();
if ($pid == -1) die('failed to fork :(');
/* child process */
if ($pid == 0)
{
/* do something */
exit(0);
}
/* parent */
else { $kids++; }
}
/* when finished, just clean up the children */
print "Reaping $kids children...\n";
while ($kids) sleep(1);
print "Finished.\n";
?>
The problem was, $kids never became zero so it would effectively wait forever. After wracking my brains (UNIX forks are new to me) I finally read the Perl IPC docs and viola, a solution! It turns out that because signal handlers are not re-entrant, my handler will not be called again while it is in use. The scenario that caused me trouble was that one child would exit and call the signal handler, which would pcntl_waitpid() it and decrement the counter. Meanwhile, another child would exit while the first child was still being reaped, so the second would never get to notify the parent!
The solution was to continually reap children from the SIGCHLD handler, so long as there were children to reap. Here is the *fixed* childFinished function:
<?php
function childFinished($signal)
{
global $kids;
while( pcntl_waitpid(-1, $status, WNOHANG) > 0 )
$kids--;
}
?>`
aeolianmeson at NOSPAXM dot blitzeclipse dot com
09-Jun-2006 01:19
`This issue occurs in at least PHP 5.1.2.
When a SIGINT is sent via CTRL+C or CTRL+BREAK, the handler is called. If this handler sends a SIGTERM to other children, the signals are not received.
SIGINT can be sent via posix_kill() and it work exactly as expected-- This only applies when initiated via a hard break.`
aeolianmeson at NOSPAM dot blitzeclipse dot com
29-May-2006 08:43
`In at least version 5.1.4, the parameter passed to the handler is not a strict integer.
I have had such problems as trying to add the signal to an array, but the array is completely screwed up when viewed (but not viewed immediately after being added). This occurs when the handler is a method (array($this, 'methodname')), or a traditional functions.
To avoid this bug, typecast the parameter to an integer:
(note that each newline may appear to just be 'n'.)
<?php
print("pid= " . posix_getpid() . "\n");
declare(ticks=1);
$arrsignals = array();
function handler($nsig)
{
global $arrsignals;
$arrsignals[] = (int)$nsig;
print("Signal caught and registered.\n");
var_dump($arrsignals);
}
pcntl_signal(SIGTERM, 'handler');
// Wait for signals from the command-line (just a simple 'kill (pid)').
$n = 15;
while($n)
{
sleep(1);
$n--;
}
print("terminated.\n\n");
var_dump($arrsignals);
?>
Dustin`
zenyatta22 at hotmail
28-Mar-2006 02:26
`Process handling is not available when using a blocking socket! Bear this in mind.`
sezer yalcin
12-Jan-2006 12:29
`You should pay attention to this issue.
I realized "some" files need specific declare() where some do not.
It is good idea to include in all "main" files, not in include files.
junkmail at konvergencia dot hu
06-May-2003 04:21
It seems like the scope of declare() when used in it's new global form e.g.
declare(ticks = 1);
is restricted to the file it is used in and the one's include() -ed or require() -ed by the script. So you can NOT do this:`
wm161 at wm161 dot net
10-Jan-2006 03:45
`When you are running a script inside of a loop that checks a socket, and it hangs on that checking (Either by flaw or design), it can't handle signals until some data is received.
A suggested workaround would be to use the stream_set_blocking function, or stream_select on the offending reads.`
erik at phpcastle dot com
27-Dec-2005 03:46
`When you want to stop a CLI script by a keyboard interupt then you should use SIGINT.
Example script:
#!/usr/bin/php5
<?php
// tick use required as of PHP 4.3.0
declare(ticks = 1);
// signal handler function
function sig_handler($signo)
{
switch ($signo) {
case SIGINT:
// handle shutdown tasks
echo "Keyboard pressed...\n";
exit;
break;
default:
// handle all other signals
}
}
echo "Installing signal handler...\n";
// setup signal handlers
pcntl_signal(SIGINT, "sig_handler");
// or use an object, available as of PHP 4.3.0
// pcntl_signal(SIGUSR1, array($obj, "do_something");
// Just a stupid simple loop
for ($i = 1; $i <= 10; $i++){
echo ".";
sleep(1);
}
echo "Done\n"
?>`
codeslinger at compsalot dot com
03-Feb-2005 09:23
`I ran into an interesting problem. CLI 4.3.10 Linux
The parent forked a child. The child did a bunch of stuff, and when it was done it sent SIGUSR1 to the parent and immediately exited.
Result:
The child turned into a zombie process waiting for the parent to harvest it, as it should.
But the parent was unable to harvest the child because it was receiving an endless barrage of SIGUSR1s. In fact, it logged over 200000 before I shut it down (SIGKILL). The parent was not able to do anything else (respond to other events) during that time.
No, it wasn't a bug in my child code. Apparently, after sending a signal there is some "behind the covers" work that needs to occur to acknowledge signal completion, and when you exit immediately it is not able to happen, so the system just keeps trying.
Solution: I introduced a small delay in the child, after sending the signal, and before exiting.
No more Sig loops...
----------
P.S. With respect to the note below. The whole point of the sleep function is to enable the processing of other events. So, yes, your non-renterent code, will suddenly get re-entered when you do a sleep, because you have just handed off control to the next pending event.
Ignoring the signal is only an option if the signal is unimportant to your program.... The better way to approach it, is to not do lengthy processing inside of the signal event. Instead set a global flag and get the heck out of there as fast as possible. Allow another part of your program to check the flag and do the processing outside of the signal event. Usually your program is in some kind of loop when it is receiving signals, so checking a flag regularly shouldn't be a problem.`
ieure at php dot net
19-Jan-2005 05:15
`Some weird signal interactions going on here. I'm running PHP 4.3.9.
sleep() calls seem to be interrupted when any signal is received by the PHP script. But things get weird when you sleep() inside a signal handler.
Ordinarily, signal handlers are non-reentrant. That is, if the signal handler is running, sending another signal has no effect. However, sleep() seems to override PHP's signal handling. If you sleep() inside a signal handler, the signal is received and the sleep() is interrupted.
This can be worked around like this:
function handler($signal)
{
// Ignore this signal
pcntl_signal($signal, SIG_IGN);
sleep(10);
// Reinstall signal handler
pcntl_signal($signal, __FUNCTION__);
}
I don't see any mention of this behavior in the documentation.`
cp at ltur dot de
09-Dec-2004 02:21
`@spam at etcpasswd dot de
Yes it is possible to use a Handler inside of a Class:
<?php
declare(ticks = 1);
class SignalHandler
{
function __construct() {
$this->_init();
}
function _init() {
pcntl_signal(SIGTERM, array(&$this,"handleSignals"));
}
function handleSignals($signal)
{
echo "$signal\n";
}
}
$o = new SignalHandler();
posix_kill(getmypid(),SIGTERM);
// prints 15
?>
HTH
.Ape`
junkmail at konvergencia dot hu
06-May-2003 04:21
`It seems like the scope of declare() when used in it's new global form e.g.
declare(ticks = 1);
is restricted to the file it is used in and the one's include() -ed or require() -ed by the script. So you can NOT do this:
main.php:
<?php
include ('signals.php');
do_something_here();
?>
signals.php:
<?php
declare(ticks = 1);
function sig_handler($signo) {
handle_the_signal_here();
}
pcntl_signal (SIGINT, 'sig_handler');
?>
Your signal handler function will not be called. In the above examples you have to declare() in the main.php file.`
daniel[at]lorch.cc
27-Feb-2002 06:17
`There are two documents I consider reading:
Unix Signals Programming
http://users.actcom.co.il/~choo/lupg/tutorials/
Beej's Guide to Unix Interprocess Communication
http://www.ecst.csuchico.edu/~beej/guide/ipc/
Also, have a look at the manpage:
http://www.mcsr.olemiss.edu/cgi-bin/man-cgi?signal+5`
add a note
pcntl_wait pcntl_setpriority

Last updated: Sat, 27 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 10:36:09 2007 PST