mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Prevent fiber switching in tick function and signal handlers (#9028)
This commit is contained in:
parent
928624ed8a
commit
2bc6025c2c
6 changed files with 127 additions and 0 deletions
37
Zend/tests/fibers/signal-async.phpt
Normal file
37
Zend/tests/fibers/signal-async.phpt
Normal file
|
@ -0,0 +1,37 @@
|
|||
--TEST--
|
||||
Prevent switching fibers when async signals are enabled
|
||||
--EXTENSIONS--
|
||||
pcntl
|
||||
posix
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
pcntl_async_signals(true);
|
||||
|
||||
pcntl_signal(SIGUSR1, function (): void {
|
||||
if (Fiber::getCurrent() !== null) {
|
||||
Fiber::suspend();
|
||||
}
|
||||
});
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
echo "Fiber start\n";
|
||||
posix_kill(posix_getpid(), SIGUSR1);
|
||||
time_nanosleep(1);
|
||||
echo "Fiber end\n";
|
||||
});
|
||||
|
||||
$fiber->start();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fiber start
|
||||
|
||||
Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in %ssignal-async.php:%d
|
||||
Stack trace:
|
||||
#0 %ssignal-async.php(%d): Fiber::suspend()
|
||||
#1 %ssignal-async.php(%d): {closure}(%d, Array)
|
||||
#2 [internal function]: {closure}()
|
||||
#3 %ssignal-async.php(%d): Fiber->start()
|
||||
#4 {main}
|
||||
thrown in %ssignal-async.php on line %d
|
46
Zend/tests/fibers/signal-dispatch.phpt
Normal file
46
Zend/tests/fibers/signal-dispatch.phpt
Normal file
|
@ -0,0 +1,46 @@
|
|||
--TEST--
|
||||
Prevent switching fibers when dispatching pending signals
|
||||
--EXTENSIONS--
|
||||
pcntl
|
||||
posix
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
pcntl_signal(SIGUSR1, function (): void {
|
||||
if (Fiber::getCurrent() !== null) {
|
||||
Fiber::suspend();
|
||||
}
|
||||
});
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
echo "Fiber start\n";
|
||||
|
||||
posix_kill(posix_getpid(), SIGUSR1);
|
||||
|
||||
try {
|
||||
pcntl_signal_dispatch();
|
||||
} catch (FiberError $e) {
|
||||
Fiber::suspend($e);
|
||||
}
|
||||
|
||||
echo "Fiber end\n";
|
||||
});
|
||||
|
||||
$e = $fiber->start();
|
||||
|
||||
echo $e, "\n";
|
||||
|
||||
$fiber->resume();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fiber start
|
||||
FiberError: Cannot switch fibers in current execution context in %ssignal-dispatch.php:%d
|
||||
Stack trace:
|
||||
#0 %ssignal-dispatch.php(%d): Fiber::suspend()
|
||||
#1 [internal function]: {closure}(%d, Array)
|
||||
#2 %ssignal-dispatch.php(%d): pcntl_signal_dispatch()
|
||||
#3 [internal function]: {closure}()
|
||||
#4 %ssignal-dispatch.php(%d): Fiber->start()
|
||||
#5 {main}
|
||||
Fiber end
|
33
Zend/tests/fibers/ticks.phpt
Normal file
33
Zend/tests/fibers/ticks.phpt
Normal file
|
@ -0,0 +1,33 @@
|
|||
--TEST--
|
||||
Prevent switching fibers in tick function
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
declare(ticks=1);
|
||||
|
||||
register_tick_function(function (): void {
|
||||
if (Fiber::getCurrent() !== null) {
|
||||
Fiber::suspend();
|
||||
}
|
||||
});
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
echo "1\n";
|
||||
echo "2\n";
|
||||
echo "3\n";
|
||||
});
|
||||
|
||||
$fiber->start();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
1
|
||||
|
||||
Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in %sticks.php:%d
|
||||
Stack trace:
|
||||
#0 %sticks.php(%d): Fiber::suspend()
|
||||
#1 %sticks.php(%d): {closure}()
|
||||
#2 [internal function]: {closure}()
|
||||
#3 %sticks.php(%d): Fiber->start()
|
||||
#4 {main}
|
||||
thrown in %sticks.php on line %d
|
|
@ -7752,7 +7752,9 @@ ZEND_VM_HANDLER(105, ZEND_TICKS, ANY, ANY, NUM)
|
|||
EG(ticks_count) = 0;
|
||||
if (zend_ticks_function) {
|
||||
SAVE_OPLINE();
|
||||
zend_fiber_switch_block();
|
||||
zend_ticks_function(opline->extended_value);
|
||||
zend_fiber_switch_unblock();
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
|
2
Zend/zend_vm_execute.h
generated
2
Zend/zend_vm_execute.h
generated
|
@ -2996,7 +2996,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_TICKS_SPEC_HANDLER(ZEND_OPCODE
|
|||
EG(ticks_count) = 0;
|
||||
if (zend_ticks_function) {
|
||||
SAVE_OPLINE();
|
||||
zend_fiber_switch_block();
|
||||
zend_ticks_function(opline->extended_value);
|
||||
zend_fiber_switch_unblock();
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "pcntl_arginfo.h"
|
||||
#include "php_signal.h"
|
||||
#include "php_ticks.h"
|
||||
#include "zend_fibers.h"
|
||||
|
||||
#if defined(HAVE_GETPRIORITY) || defined(HAVE_SETPRIORITY) || defined(HAVE_WAIT3)
|
||||
#include <sys/wait.h>
|
||||
|
@ -1410,6 +1411,9 @@ void pcntl_signal_dispatch()
|
|||
return;
|
||||
}
|
||||
|
||||
/* Prevent switching fibers when handling signals */
|
||||
zend_fiber_switch_block();
|
||||
|
||||
/* Prevent reentrant handler calls */
|
||||
PCNTL_G(processing_signal_queue) = 1;
|
||||
|
||||
|
@ -1450,6 +1454,9 @@ void pcntl_signal_dispatch()
|
|||
/* Re-enable queue */
|
||||
PCNTL_G(processing_signal_queue) = 0;
|
||||
|
||||
/* Re-enable fiber switching */
|
||||
zend_fiber_switch_unblock();
|
||||
|
||||
/* return signal mask to previous state */
|
||||
sigprocmask(SIG_SETMASK, &old_mask, NULL);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue