Skip to content

Commit 2709e49

Browse files
committed
Move observer to zend_observer, add tests in zend_test
1 parent bf7671f commit 2709e49

11 files changed

+345
-26
lines changed

Zend/zend_fibers.c

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "zend_interfaces.h"
2525
#include "zend_exceptions.h"
2626
#include "zend_builtin_functions.h"
27+
#include "zend_observer.h"
2728

2829
#include "zend_fibers.h"
2930
#include "zend_fibers_arginfo.h"
@@ -46,8 +47,6 @@ static zend_object_handlers zend_fiber_handlers;
4647
static zend_object *zend_fiber_object_create(zend_class_entry *ce);
4748
static void zend_fiber_object_destroy(zend_object *object);
4849

49-
static zend_llist zend_fiber_observers_list;
50-
5150
typedef void *fcontext_t;
5251

5352
typedef struct _transfer_t {
@@ -88,22 +87,6 @@ extern transfer_t jump_fcontext(fcontext_t to, void *vp);
8887

8988

9089

91-
ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler)
92-
{
93-
zend_llist_add_element(&zend_fiber_observers_list, &handler);
94-
}
95-
96-
static zend_always_inline void zend_observer_fiber_switch_notify(zend_fiber *from, zend_fiber *to)
97-
{
98-
zend_llist_element *element;
99-
zend_observer_fiber_switch_handler callback;
100-
101-
for (element = zend_fiber_observers_list.head; element; element = element->next) {
102-
callback = *(zend_observer_fiber_switch_handler *) element->data;
103-
callback(from, to);
104-
}
105-
}
106-
10790
static size_t zend_fiber_page_size()
10891
{
10992
#if _POSIX_MAPPED_FILES
@@ -362,6 +345,8 @@ static void ZEND_STACK_ALIGNED zend_fiber_execute(zend_fiber_context *context)
362345
// Reference added while running, removed when suspended, and added again once resumed.
363346
GC_ADDREF(&fiber->std);
364347

348+
fiber->status = ZEND_FIBER_STATUS_RUNNING;
349+
365350
zend_call_function(&fiber->fci, &fiber->fci_cache);
366351

367352
if (EG(exception)) {
@@ -480,8 +465,6 @@ ZEND_METHOD(Fiber, start)
480465
RETURN_THROWS();
481466
}
482467

483-
fiber->status = ZEND_FIBER_STATUS_RUNNING;
484-
485468
zend_fiber_switch_to(fiber);
486469

487470
zval_ptr_dtor(&fiber->fci.function_name);
@@ -736,11 +719,9 @@ void zend_fiber_init(void)
736719
EG(fiber_error) = NULL;
737720

738721
zend_hash_init(&EG(fibers), 0, NULL, NULL, 0);
739-
zend_llist_init(&zend_fiber_observers_list, sizeof(zend_observer_fiber_switch_handler), NULL, 0);
740722
}
741723

742724
void zend_fiber_shutdown(void)
743725
{
744726
zend_hash_destroy(&EG(fibers));
745-
zend_llist_destroy(&zend_fiber_observers_list);
746727
}

Zend/zend_fibers.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,6 @@ typedef struct _zend_fiber_error {
8383
zend_string *message;
8484
} zend_fiber_error;
8585

86-
typedef void (*zend_observer_fiber_switch_handler)(zend_fiber *from, zend_fiber *to);
87-
88-
ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler);
89-
9086
static const zend_uchar ZEND_FIBER_STATUS_INIT = 0x0;
9187
static const zend_uchar ZEND_FIBER_STATUS_SUSPENDED = 0x1;
9288
static const zend_uchar ZEND_FIBER_STATUS_RUNNING = 0x2;

Zend/zend_observer.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ typedef struct _zend_observer_fcall_data {
4040

4141
zend_llist zend_observers_fcall_list;
4242
zend_llist zend_observer_error_callbacks;
43+
zend_llist zend_observer_fiber_switch;
4344

4445
int zend_observer_fcall_op_array_extension = -1;
4546

@@ -72,6 +73,7 @@ ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init) {
7273
ZEND_API void zend_observer_startup(void) {
7374
zend_llist_init(&zend_observers_fcall_list, sizeof(zend_observer_fcall_init), NULL, 1);
7475
zend_llist_init(&zend_observer_error_callbacks, sizeof(zend_observer_error_cb), NULL, 1);
76+
zend_llist_init(&zend_observer_fiber_switch, sizeof(zend_observer_fiber_switch_handler), NULL, 1);
7577
}
7678

7779
ZEND_API void zend_observer_activate(void) {
@@ -89,6 +91,7 @@ ZEND_API void zend_observer_deactivate(void) {
8991
ZEND_API void zend_observer_shutdown(void) {
9092
zend_llist_destroy(&zend_observers_fcall_list);
9193
zend_llist_destroy(&zend_observer_error_callbacks);
94+
zend_llist_destroy(&zend_observer_fiber_switch);
9295
}
9396

9497
static void zend_observer_fcall_install(zend_execute_data *execute_data) {
@@ -255,3 +258,19 @@ void zend_observer_error_notify(int type, const char *error_filename, uint32_t e
255258
callback(type, error_filename, error_lineno, message);
256259
}
257260
}
261+
262+
ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler)
263+
{
264+
zend_llist_add_element(&zend_observer_fiber_switch, &handler);
265+
}
266+
267+
void zend_observer_fiber_switch_notify(zend_fiber *from, zend_fiber *to)
268+
{
269+
zend_llist_element *element;
270+
zend_observer_fiber_switch_handler callback;
271+
272+
for (element = zend_observer_fiber_switch.head; element; element = element->next) {
273+
callback = *(zend_observer_fiber_switch_handler *) element->data;
274+
callback(from, to);
275+
}
276+
}

Zend/zend_observer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "zend.h"
2424
#include "zend_compile.h"
25+
#include "zend_fibers.h"
2526

2627
BEGIN_EXTERN_C()
2728

@@ -77,6 +78,11 @@ typedef void (*zend_observer_error_cb)(int type, const char *error_filename, uin
7778
ZEND_API void zend_observer_error_register(zend_observer_error_cb callback);
7879
void zend_observer_error_notify(int type, const char *error_filename, uint32_t error_lineno, zend_string *message);
7980

81+
typedef void (*zend_observer_fiber_switch_handler)(zend_fiber *from, zend_fiber *to);
82+
83+
ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler);
84+
void zend_observer_fiber_switch_notify(zend_fiber *from, zend_fiber *to);
85+
8086
END_EXTERN_C()
8187

8288
#endif /* ZEND_OBSERVER_H */

ext/zend_test/test.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "zend_attributes.h"
2828
#include "zend_observer.h"
2929
#include "zend_smart_str.h"
30+
#include "zend_fibers.h"
3031

3132
ZEND_BEGIN_MODULE_GLOBALS(zend_test)
3233
int observer_enabled;
@@ -40,6 +41,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
4041
int observer_show_opcode;
4142
char *observer_show_opcode_in_user_handler;
4243
int observer_nesting_depth;
44+
int observer_fiber_switch;
4345
int replace_zend_execute_ex;
4446
ZEND_END_MODULE_GLOBALS(zend_test)
4547

@@ -348,6 +350,7 @@ PHP_INI_BEGIN()
348350
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
349351
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
350352
STD_PHP_INI_ENTRY("zend_test.observer.show_opcode_in_user_handler", "", PHP_INI_SYSTEM, OnUpdateString, observer_show_opcode_in_user_handler, zend_zend_test_globals, zend_test_globals)
353+
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_switch", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_switch, zend_zend_test_globals, zend_test_globals)
351354
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
352355
PHP_INI_END()
353356

@@ -395,6 +398,45 @@ static void observer_set_user_opcode_handler(const char *opcode_names, user_opco
395398
}
396399
}
397400

401+
static void fiber_address_observer(zend_fiber *from, zend_fiber *to)
402+
{
403+
if (ZT_G(observer_fiber_switch)) {
404+
php_printf("<!-- switching from fiber %lx to %lx -->\n", (uintptr_t) from, (uintptr_t) to);
405+
}
406+
}
407+
408+
static void fiber_enter_observer(zend_fiber *from, zend_fiber *to)
409+
{
410+
if (ZT_G(observer_fiber_switch)) {
411+
if (to) {
412+
if (to->status == ZEND_FIBER_STATUS_INIT) {
413+
php_printf("<init '%lx'>\n", (uintptr_t) to);
414+
} else if (to->status == ZEND_FIBER_STATUS_RUNNING && (!from || from->status == ZEND_FIBER_STATUS_RUNNING)) {
415+
php_printf("<resume '%lx'>\n", (uintptr_t) to);
416+
} else if (to->status == ZEND_FIBER_STATUS_SHUTDOWN) {
417+
php_printf("<destroying '%lx'>\n", (uintptr_t) to);
418+
}
419+
}
420+
}
421+
}
422+
423+
static void fiber_suspend_observer(zend_fiber *from, zend_fiber *to)
424+
{
425+
if (ZT_G(observer_fiber_switch)) {
426+
if (from) {
427+
if (from->status == ZEND_FIBER_STATUS_SUSPENDED) {
428+
php_printf("<suspend '%lx'>\n", (uintptr_t) from);
429+
} else if (from->status == ZEND_FIBER_STATUS_RETURNED) {
430+
php_printf("<returned '%lx'>\n", (uintptr_t) from);
431+
} else if (from->status == ZEND_FIBER_STATUS_THREW) {
432+
php_printf("<threw '%lx'>\n", (uintptr_t) from);
433+
} else if (from->status == ZEND_FIBER_STATUS_SHUTDOWN) {
434+
php_printf("<destroyed '%lx'>\n", (uintptr_t) from);
435+
}
436+
}
437+
}
438+
}
439+
398440
PHP_MINIT_FUNCTION(zend_test)
399441
{
400442
zend_test_interface = register_class__ZendTestInterface();
@@ -442,6 +484,12 @@ PHP_MINIT_FUNCTION(zend_test)
442484
observer_set_user_opcode_handler(ZT_G(observer_show_opcode_in_user_handler), observer_show_opcode_in_user_handler);
443485
}
444486

487+
if (ZT_G(observer_enabled)) {
488+
zend_observer_fiber_switch_register(fiber_address_observer);
489+
zend_observer_fiber_switch_register(fiber_enter_observer);
490+
zend_observer_fiber_switch_register(fiber_suspend_observer);
491+
}
492+
445493
return SUCCESS;
446494
}
447495

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Observer: Basic fiber switching
3+
--SKIPIF--
4+
<?php if (!extension_loaded('zend_test')) die('skip: zend_test extension required'); ?>
5+
--INI--
6+
zend_test.observer.enabled=1
7+
zend_test.observer.fiber_switch=1
8+
--FILE--
9+
<?php
10+
11+
$fiber = new Fiber(function (): void {
12+
Fiber::suspend();
13+
});
14+
15+
$fiber->start();
16+
$fiber->resume();
17+
18+
?>
19+
--EXPECTF--
20+
<!-- init '%sobserver_fiber_01.php' -->
21+
<!-- switching from fiber 0 to %x -->
22+
<init '%x'>
23+
<!-- init {closure}() -->
24+
<!-- switching from fiber %x to 0 -->
25+
<suspend '%x'>
26+
<!-- switching from fiber 0 to %x -->
27+
<resume '%x'>
28+
<!-- switching from fiber %x to 0 -->
29+
<returned '%x'>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Observer: Unfinished fiber
3+
--SKIPIF--
4+
<?php if (!extension_loaded('zend_test')) die('skip: zend_test extension required'); ?>
5+
--INI--
6+
zend_test.observer.enabled=1
7+
zend_test.observer.fiber_switch=1
8+
--FILE--
9+
<?php
10+
11+
$fiber = new Fiber(function (): void {
12+
Fiber::suspend();
13+
});
14+
15+
$fiber->start();
16+
17+
?>
18+
--EXPECTF--
19+
<!-- init '%sobserver_fiber_02.php' -->
20+
<!-- switching from fiber 0 to %x -->
21+
<init '%x'>
22+
<!-- init {closure}() -->
23+
<!-- switching from fiber %x to 0 -->
24+
<suspend '%x'>
25+
<!-- switching from fiber 0 to %x -->
26+
<destroying '%x'>
27+
<!-- switching from fiber %x to 0 -->
28+
<destroyed '%x'>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
--TEST--
2+
Observer: Nested fibers
3+
--SKIPIF--
4+
<?php if (!extension_loaded('zend_test')) die('skip: zend_test extension required'); ?>
5+
--INI--
6+
zend_test.observer.enabled=1
7+
zend_test.observer.fiber_switch=1
8+
--FILE--
9+
<?php
10+
11+
$fiber = new Fiber(function (): void {
12+
Fiber::suspend();
13+
var_dump(1);
14+
15+
$fiber = new Fiber(function (): void {
16+
Fiber::suspend();
17+
var_dump(3);
18+
Fiber::suspend();
19+
var_dump(5);
20+
});
21+
22+
$fiber->start();
23+
24+
Fiber::suspend();
25+
var_dump(2);
26+
27+
$fiber->resume();
28+
29+
Fiber::suspend();
30+
var_dump(4);
31+
32+
$fiber->resume();
33+
});
34+
35+
$fiber->start();
36+
$fiber->resume();
37+
$fiber->resume();
38+
$fiber->resume();
39+
40+
?>
41+
--EXPECTF--
42+
<!-- init '%sobserver_fiber_03.php' -->
43+
<!-- switching from fiber 0 to %x -->
44+
<init '%x'>
45+
<!-- init {closure}() -->
46+
<!-- switching from fiber %x to 0 -->
47+
<suspend '%x'>
48+
<!-- switching from fiber 0 to %x -->
49+
<resume '%x'>
50+
int(1)
51+
<!-- switching from fiber %x to %x -->
52+
<init '%x'>
53+
<!-- init {closure}() -->
54+
<!-- switching from fiber %x to %x -->
55+
<suspend '%x'>
56+
<!-- switching from fiber %x to 0 -->
57+
<suspend '%x'>
58+
<!-- switching from fiber 0 to %x -->
59+
<resume '%x'>
60+
int(2)
61+
<!-- switching from fiber %x to %x -->
62+
<resume '%x'>
63+
int(3)
64+
<!-- switching from fiber %x to %x -->
65+
<suspend '%x'>
66+
<!-- switching from fiber %x to 0 -->
67+
<suspend '%x'>
68+
<!-- switching from fiber 0 to %x -->
69+
<resume '%x'>
70+
int(4)
71+
<!-- switching from fiber %x to %x -->
72+
<resume '%x'>
73+
int(5)
74+
<!-- switching from fiber %x to %x -->
75+
<returned '%x'>
76+
<!-- switching from fiber %x to 0 -->
77+
<returned '%x'>

0 commit comments

Comments
 (0)