Skip to content

Instantly share code, notes, and snippets.

@jsjohnst
Created August 8, 2012 19:18
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jsjohnst/3297804 to your computer and use it in GitHub Desktop.
Save jsjohnst/3297804 to your computer and use it in GitHub Desktop.
<?php
declare(ticks = 1);
class TimeoutException extends Exception {};
function signal_handler($signal) {
throw new TimeoutException();
}
pcntl_signal(SIGALRM, "signal_handler", true);
pcntl_alarm(1);
try {
// simulate long executing block
while(1) sleep(30);
} catch(TimeoutException $e) {
echo "Timeout exceeded";
}
echo "done";
@mahadazad
Copy link

Hi,
can you please explain what the code does.

thank you

@dave-newson
Copy link

Some more info, because this is one of the highest results on Google for pcntl_alarm:

declare(ticks = 1); tells the parser to enable the "tick" event per statement in your code.
You must set this, otherwise pcntl_alarm won't get called periodically, and it'll never fire its interrupts.

pcntl_signal(SIGALRM, "signal_handler", true); sets up a signal that's triggered by SIGALRM (pcntl_alarm). When SIGALRM is triggered, the signal_handler function is called.

pcntl_alarm(1); says to trigger the SIGALRM signal in 1 second. It will only alarm once.

In the try/catch block, we're just sleeping for 30 seconds, in an infinite while loop. We won't ever exit until the TimeoutException is thrown.
What happens, is pcntl_alarm fires after one second, and pcntl_signal fires signal_handler. This function throws a TimeoutException. The execution happens in the context of the while loop, so the exception bubbles up into the try/catch statement.
The result, is after 1s the application exists.

Some fun things to note:

  • pcntl_alarm(1); only causes an interrupt once. You need to call it again to make subsequent interrupts occur.
  • sleep() can be interrupted by the alarm signal. This is not true for all functions.
  • sleep() will not resume after the alarm signal. Try replacing the throw inside signal_handler with echo "derp"; pcntl_alarm(1); and you'll see "derp" printed every 1 second.
  • declare(ticks = 1) provides an instruction to the php parser. It will apply to every file after you have set it. This makes the order of file inclusion important. If you don't want it to apply, you can always set it back to 0 at the end of the file you need it in.
  • For files where ticks is not set (before it's set, or set back to 0), ticks will not be observed because the interrupt events are not written into the opcode. The alarm will only occur after execution returns to a file that has ticks set.
  • Where ticks have been enabled, sub-routines inside other classes or files will be interrupted by the alarm event, and resume cleanly.
  • In my benchmarking, there was no discernible performance hit with declare(ticks=1) set (approx 1mil md5 ops in a loop).

@aldeek
Copy link

aldeek commented Mar 31, 2020

How after hour?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment