Skip to content

Commit 26d8a62

Browse files
committed
Refactor Fiber garbage collection and NULL value handling
1 parent 6118041 commit 26d8a62

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

Zend/zend_fibers.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,18 +1032,17 @@ static void coroutine_entry_point(void)
10321032
}
10331033
zend_catch
10341034
{
1035-
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
10361035
is_bailout = true;
10371036
}
10381037
zend_end_try();
10391038

10401039
zend_try
10411040
{
1042-
zend_fiber_event * yield_event = fiber->yield_event;
1041+
fiber = coroutine->extended_data;
10431042
zend_async_event_t * yield_event_base = NULL;
10441043

1045-
if (yield_event) {
1046-
yield_event_base = &yield_event->base;
1044+
if (fiber && fiber->yield_event) {
1045+
yield_event_base = &fiber->yield_event->base;
10471046
}
10481047

10491048
//
@@ -1095,14 +1094,19 @@ static void coroutine_entry_point(void)
10951094
}
10961095
zend_catch
10971096
{
1098-
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
10991097
is_bailout = true;
11001098
}
11011099
zend_end_try();
11021100

1103-
/* Cleanup callback and unset field to prevent GC / duplicate dtor issues. */
1104-
zval_ptr_dtor(&fiber->fci.function_name);
1105-
ZVAL_UNDEF(&fiber->fci.function_name);
1101+
if (fiber) {
1102+
if (is_bailout) {
1103+
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
1104+
}
1105+
1106+
/* Cleanup callback and unset field to prevent GC / duplicate dtor issues. */
1107+
zval_ptr_dtor(&fiber->fci.function_name);
1108+
ZVAL_UNDEF(&fiber->fci.function_name);
1109+
}
11061110

11071111
if (is_bailout) {
11081112
zend_bailout();
@@ -1237,8 +1241,26 @@ static void zend_fiber_object_destroy(zend_object *object)
12371241
}
12381242

12391243
if (fiber->coroutine != NULL) {
1240-
ZEND_ASYNC_EVENT_RELEASE(&fiber->coroutine->event);
1244+
1245+
//
1246+
// A situation is possible where a Fiber is destroyed earlier than the coroutine,
1247+
// while the coroutine is already running. In this case, we cancel the coroutine.
1248+
//
1249+
zend_coroutine_t *coroutine = fiber->coroutine;
12411250
fiber->coroutine = NULL;
1251+
coroutine->extended_data = NULL;
1252+
1253+
if (ZEND_COROUTINE_IS_FINISHED(coroutine)) {
1254+
ZEND_ASYNC_EVENT_RELEASE(&coroutine->event);
1255+
return;
1256+
}
1257+
1258+
zend_object *exception = zend_async_new_exception(
1259+
ZEND_ASYNC_EXCEPTION_CANCELLATION, "Fiber has been destroyed"
1260+
);
1261+
1262+
ZEND_ASYNC_CANCEL(coroutine, exception, true);
1263+
12421264
return;
12431265
}
12441266

0 commit comments

Comments
 (0)