|
23 | 23 | #include "zend_variables.h"
|
24 | 24 | #include "zend_API.h"
|
25 | 25 | #include "zend_objects_API.h"
|
| 26 | + |
| 27 | +#include "zend_async_API.h" |
26 | 28 | #include "zend_fibers.h"
|
27 | 29 |
|
28 | 30 | ZEND_API void ZEND_FASTCALL zend_objects_store_init(zend_objects_store *objects, uint32_t init_size)
|
@@ -63,6 +65,93 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_call_destructors(zend_objects_sto
|
63 | 65 | }
|
64 | 66 | }
|
65 | 67 |
|
| 68 | +#ifdef PHP_ASYNC_API |
| 69 | +static void store_call_destructors_coroutine_dtor(zend_coroutine_t *coroutine) |
| 70 | +{ |
| 71 | + zend_shutdown_context_t *shutdown_context = &EG(shutdown_context); |
| 72 | + |
| 73 | + if (shutdown_context->coroutine == coroutine) { |
| 74 | + shutdown_context->coroutine = NULL; |
| 75 | + zend_error(E_CORE_ERROR, "Shutdown destructors coroutine was not finished property"); |
| 76 | + shutdown_destructors(); |
| 77 | + } |
| 78 | +} |
| 79 | + |
| 80 | +static void store_call_destructors_entry(void) |
| 81 | +{ |
| 82 | + zend_objects_store_call_destructors_async(&EG(objects_store)); |
| 83 | +} |
| 84 | + |
| 85 | +static bool store_call_destructors_context_switch_handler( |
| 86 | + zend_coroutine_t *coroutine, |
| 87 | + bool is_enter, |
| 88 | + bool is_finishing |
| 89 | +) { |
| 90 | + if (is_enter) { |
| 91 | + return true; |
| 92 | + } |
| 93 | + |
| 94 | + if (is_finishing) { |
| 95 | + return false; |
| 96 | + } |
| 97 | + |
| 98 | + zend_coroutine_t *shutdown_coroutine = ZEND_ASYNC_SPAWN_WITH_SCOPE_EX(ZEND_ASYNC_MAIN_SCOPE, 1); |
| 99 | + shutdown_coroutine->internal_entry = store_call_destructors_entry; |
| 100 | + shutdown_coroutine->extended_dispose = store_call_destructors_coroutine_dtor; |
| 101 | + |
| 102 | + return false; |
| 103 | +} |
| 104 | + |
| 105 | +ZEND_API void ZEND_FASTCALL zend_objects_store_call_destructors_async(zend_objects_store *objects) |
| 106 | +{ |
| 107 | + if (objects->top <= 1) { |
| 108 | + return; |
| 109 | + } |
| 110 | + |
| 111 | + EG(flags) |= EG_FLAGS_OBJECT_STORE_NO_REUSE; |
| 112 | + |
| 113 | + zend_class_entry *coroutine_ce = ZEND_ASYNC_GET_CE(ZEND_ASYNC_CLASS_COROUTINE); |
| 114 | + |
| 115 | + zend_coroutine_t *coroutine = ZEND_ASYNC_CURRENT_COROUTINE; |
| 116 | + |
| 117 | + zend_shutdown_context_t *shutdown_context = &EG(shutdown_context); |
| 118 | + |
| 119 | + if (coroutine == NULL) { |
| 120 | + ZEND_ASYNC_ADD_MAIN_COROUTINE_START_HANDLER(store_call_destructors_context_switch_handler); |
| 121 | + } else { |
| 122 | + ZEND_COROUTINE_ADD_SWITCH_HANDLER(coroutine, store_call_destructors_context_switch_handler); |
| 123 | + } |
| 124 | + |
| 125 | + if (false == shutdown_context->is_started) { |
| 126 | + shutdown_context->is_started = true; |
| 127 | + shutdown_context->coroutine = coroutine; |
| 128 | + shutdown_context->idx = 1; |
| 129 | + } |
| 130 | + |
| 131 | + for (uint32_t i = shutdown_context->idx; i < objects->top; i++) { |
| 132 | + zend_object *obj = objects->object_buckets[i]; |
| 133 | + if (IS_OBJ_VALID(obj) && obj->ce != coroutine_ce) { |
| 134 | + if (!(OBJ_FLAGS(obj) & IS_OBJ_DESTRUCTOR_CALLED)) { |
| 135 | + GC_ADD_FLAGS(obj, IS_OBJ_DESTRUCTOR_CALLED); |
| 136 | + |
| 137 | + if (obj->handlers->dtor_obj != zend_objects_destroy_object || obj->ce->destructor) { |
| 138 | + shutdown_context->idx = i; |
| 139 | + GC_ADDREF(obj); |
| 140 | + obj->handlers->dtor_obj(obj); |
| 141 | + GC_DELREF(obj); |
| 142 | + |
| 143 | + if (coroutine != ZEND_ASYNC_CURRENT_COROUTINE) { |
| 144 | + return; |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + shutdown_context->is_started = false; |
| 152 | +} |
| 153 | +#endif |
| 154 | + |
66 | 155 | ZEND_API void ZEND_FASTCALL zend_objects_store_mark_destructed(zend_objects_store *objects)
|
67 | 156 | {
|
68 | 157 | if (objects->object_buckets && objects->top > 1) {
|
|
0 commit comments