Skip to content

Commit

Permalink
Fix pcntl_signal() restore when pcntl_alarm() is set
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Dec 15, 2024
1 parent fde7289 commit f25a895
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 11 deletions.
23 changes: 12 additions & 11 deletions src/Util/PcntlTimeout.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,22 @@ public function __construct(int $timeout)
*/
public function timeBoxed(callable $code)
{
$existingHandler = pcntl_signal_get_handler(\SIGALRM);
if (pcntl_alarm($this->timeout) !== 0) {
throw new LockAcquireException('Existing process alarm is not supported');
}

$origSignalHandler = pcntl_signal_get_handler(\SIGALRM);

$signal = pcntl_signal(\SIGALRM, function (): void {
$timeout = $this->timeout;
$signalHandlerFx = static function () use ($timeout): void {
throw new DeadlineException(sprintf(
'Timebox hit deadline of %d seconds',
$this->timeout
$timeout
));
});
if (!$signal) {
throw new LockAcquireException('Could not install signal handler');
}
};

$oldAlarm = pcntl_alarm($this->timeout);
if ($oldAlarm !== 0) {
throw new LockAcquireException('Existing alarm was not expected');
if (!pcntl_signal(\SIGALRM, $signalHandlerFx)) {
throw new LockAcquireException('Failed to install signal handler');
}

try {
Expand All @@ -83,7 +84,7 @@ public function timeBoxed(callable $code)
try {
pcntl_signal_dispatch();
} finally {
pcntl_signal(\SIGALRM, $existingHandler);
pcntl_signal(\SIGALRM, $origSignalHandler);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions tests/Util/PcntlTimeoutTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,19 @@ public function testShouldNotTimeout(): void
*/
public function testShouldFailOnExistingAlarm(): void
{
$origSignalHandler = pcntl_signal_get_handler(\SIGALRM);
try {
pcntl_alarm(1);
$timeout = new PcntlTimeout(1);

$this->expectException(LockAcquireException::class);
$this->expectExceptionMessage('Existing process alarm is not supported');
$timeout->timeBoxed(static function () {
sleep(1);
});
} finally {
pcntl_alarm(0);
self::assertSame($origSignalHandler, pcntl_signal_get_handler(\SIGALRM));
}
}

Expand Down

0 comments on commit f25a895

Please sign in to comment.