mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Add proper handling to observe functions in fibers
The current_observed_frame is carried along the fiber context and thus always correct now. Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
This commit is contained in:
parent
dc5475c191
commit
da94baf31a
6 changed files with 210 additions and 2 deletions
|
@ -88,6 +88,9 @@ struct _zend_fiber_context {
|
|||
/* Fiber status. */
|
||||
zend_fiber_status status;
|
||||
|
||||
/* Observer state */
|
||||
zend_execute_data *top_observed_frame;
|
||||
|
||||
/* Reserved for extensions */
|
||||
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
|
||||
};
|
||||
|
|
|
@ -39,7 +39,6 @@ zend_llist zend_observer_fiber_destroy;
|
|||
|
||||
int zend_observer_fcall_op_array_extension;
|
||||
|
||||
ZEND_TLS zend_execute_data *first_observed_frame;
|
||||
ZEND_TLS zend_execute_data *current_observed_frame;
|
||||
|
||||
// Call during minit/startup ONLY
|
||||
|
@ -95,7 +94,6 @@ ZEND_API void zend_observer_post_startup(void)
|
|||
|
||||
ZEND_API void zend_observer_activate(void)
|
||||
{
|
||||
first_observed_frame = NULL;
|
||||
current_observed_frame = NULL;
|
||||
}
|
||||
|
||||
|
@ -321,6 +319,8 @@ ZEND_API void ZEND_FASTCALL zend_observer_fiber_init_notify(zend_fiber_context *
|
|||
zend_llist_element *element;
|
||||
zend_observer_fiber_init_handler callback;
|
||||
|
||||
initializing->top_observed_frame = NULL;
|
||||
|
||||
for (element = zend_observer_fiber_init.head; element; element = element->next) {
|
||||
callback = *(zend_observer_fiber_init_handler *) element->data;
|
||||
callback(initializing);
|
||||
|
@ -332,10 +332,17 @@ ZEND_API void ZEND_FASTCALL zend_observer_fiber_switch_notify(zend_fiber_context
|
|||
zend_llist_element *element;
|
||||
zend_observer_fiber_switch_handler callback;
|
||||
|
||||
if (from->status == ZEND_FIBER_STATUS_DEAD) {
|
||||
zend_observer_fcall_end_all(); // fiber is either finished (call will do nothing) or has bailed out
|
||||
}
|
||||
|
||||
for (element = zend_observer_fiber_switch.head; element; element = element->next) {
|
||||
callback = *(zend_observer_fiber_switch_handler *) element->data;
|
||||
callback(from, to);
|
||||
}
|
||||
|
||||
from->top_observed_frame = current_observed_frame;
|
||||
current_observed_frame = to->top_observed_frame;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fiber_destroy_notify(zend_fiber_context *destroying)
|
||||
|
|
|
@ -756,6 +756,7 @@ PHP_MSHUTDOWN_FUNCTION(zend_test)
|
|||
PHP_RINIT_FUNCTION(zend_test)
|
||||
{
|
||||
zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
|
||||
ZT_G(observer_nesting_depth) = 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
59
ext/zend_test/tests/observer_fiber_functions_01.phpt
Normal file
59
ext/zend_test/tests/observer_fiber_functions_01.phpt
Normal file
|
@ -0,0 +1,59 @@
|
|||
--TEST--
|
||||
Observer: Basic function observing in fibers
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend_test.observer.enabled=1
|
||||
zend_test.observer.observe_all=1
|
||||
zend_test.observer.fiber_init=1
|
||||
zend_test.observer.fiber_switch=1
|
||||
zend_test.observer.fiber_destroy=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
var_dump(1);
|
||||
Fiber::suspend();
|
||||
var_dump(2);
|
||||
});
|
||||
|
||||
$fiber->start();
|
||||
$fiber->resume();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<!-- init '%s' -->
|
||||
<file '%s'>
|
||||
<!-- init Fiber::__construct() -->
|
||||
<Fiber::__construct>
|
||||
</Fiber::__construct>
|
||||
<!-- init Fiber::start() -->
|
||||
<Fiber::start>
|
||||
<!-- alloc: %s -->
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<init '%s'>
|
||||
<!-- init {closure}() -->
|
||||
<{closure}>
|
||||
<!-- init var_dump() -->
|
||||
<var_dump>
|
||||
int(1)
|
||||
</var_dump>
|
||||
<!-- init Fiber::suspend() -->
|
||||
<Fiber::suspend>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<suspend '%s'>
|
||||
</Fiber::start>
|
||||
<!-- init Fiber::resume() -->
|
||||
<Fiber::resume>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<resume '%s'>
|
||||
</Fiber::suspend>
|
||||
<var_dump>
|
||||
int(2)
|
||||
</var_dump>
|
||||
</{closure}>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<returned '%s'>
|
||||
<!-- destroy: %s -->
|
||||
</Fiber::resume>
|
||||
</file '%s'>
|
54
ext/zend_test/tests/observer_fiber_functions_02.phpt
Normal file
54
ext/zend_test/tests/observer_fiber_functions_02.phpt
Normal file
|
@ -0,0 +1,54 @@
|
|||
--TEST--
|
||||
Observer: Function observing in fibers with unfinished fiber
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend_test.observer.enabled=1
|
||||
zend_test.observer.observe_all=1
|
||||
zend_test.observer.fiber_init=1
|
||||
zend_test.observer.fiber_switch=1
|
||||
zend_test.observer.fiber_destroy=1
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
var_dump(1);
|
||||
Fiber::suspend();
|
||||
var_dump(2);
|
||||
});
|
||||
|
||||
$fiber->start();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<!-- init '%s' -->
|
||||
<file '%s'>
|
||||
<!-- init Fiber::__construct() -->
|
||||
<Fiber::__construct>
|
||||
</Fiber::__construct>
|
||||
<!-- init Fiber::start() -->
|
||||
<Fiber::start>
|
||||
<!-- alloc: %s -->
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<init '%s'>
|
||||
<!-- init {closure}() -->
|
||||
<{closure}>
|
||||
<!-- init var_dump() -->
|
||||
<var_dump>
|
||||
int(1)
|
||||
</var_dump>
|
||||
<!-- init Fiber::suspend() -->
|
||||
<Fiber::suspend>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<suspend '%s'>
|
||||
</Fiber::start>
|
||||
</file '%s'>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<destroying '%s'>
|
||||
<!-- Exception: GracefulExit -->
|
||||
</Fiber::suspend>
|
||||
<!-- Exception: GracefulExit -->
|
||||
</{closure}>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<destroyed '%s'>
|
||||
<!-- destroy: %s -->
|
84
ext/zend_test/tests/observer_fiber_functions_03.phpt
Normal file
84
ext/zend_test/tests/observer_fiber_functions_03.phpt
Normal file
|
@ -0,0 +1,84 @@
|
|||
--TEST--
|
||||
Observer: Function observing in fibers with bailout in fiber
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
zend_test.observer.enabled=1
|
||||
zend_test.observer.observe_all=1
|
||||
zend_test.observer.fiber_init=1
|
||||
zend_test.observer.fiber_switch=1
|
||||
zend_test.observer.fiber_destroy=1
|
||||
memory_limit=100M
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$notBailedOutFiber = new Fiber(function (): void {
|
||||
var_dump(1);
|
||||
Fiber::suspend();
|
||||
});
|
||||
|
||||
$notBailedOutFiber->start();
|
||||
|
||||
$fiber = new Fiber(function (): void {
|
||||
var_dump(2);
|
||||
Fiber::suspend();
|
||||
str_repeat('A', 200_000_000);
|
||||
});
|
||||
|
||||
$fiber->start();
|
||||
$fiber->resume();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
<!-- init '%s' -->
|
||||
<file '%s'>
|
||||
<!-- init Fiber::__construct() -->
|
||||
<Fiber::__construct>
|
||||
</Fiber::__construct>
|
||||
<!-- init Fiber::start() -->
|
||||
<Fiber::start>
|
||||
<!-- alloc: %s -->
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<init '%s'>
|
||||
<!-- init {closure}() -->
|
||||
<{closure}>
|
||||
<!-- init var_dump() -->
|
||||
<var_dump>
|
||||
int(1)
|
||||
</var_dump>
|
||||
<!-- init Fiber::suspend() -->
|
||||
<Fiber::suspend>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<suspend '%s'>
|
||||
</Fiber::start>
|
||||
<Fiber::__construct>
|
||||
</Fiber::__construct>
|
||||
<Fiber::start>
|
||||
<!-- alloc: %s -->
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<init '%s'>
|
||||
<!-- init {closure}() -->
|
||||
<{closure}>
|
||||
<var_dump>
|
||||
int(2)
|
||||
</var_dump>
|
||||
<Fiber::suspend>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<suspend '%s'>
|
||||
</Fiber::start>
|
||||
<!-- init Fiber::resume() -->
|
||||
<Fiber::resume>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<resume '%s'>
|
||||
</Fiber::suspend>
|
||||
<!-- init str_repeat() -->
|
||||
<str_repeat>
|
||||
|
||||
Fatal error: Allowed memory size of 104857600 bytes exhausted %s on line %d
|
||||
</str_repeat>
|
||||
</{closure}>
|
||||
<!-- switching from fiber %s to %s -->
|
||||
<returned '%s'>
|
||||
<!-- destroy: %s -->
|
||||
</Fiber::resume>
|
||||
</file '%s'>
|
Loading…
Add table
Add a link
Reference in a new issue