Skip to content

Commit edf53f7

Browse files
committed
Implement yield state tracking for fiber coroutines and update cancellation logic
1 parent bf3fbc8 commit edf53f7

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

scheduler.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,48 @@ static bool resolve_deadlocks(void)
526526
return false;
527527
}
528528

529+
//
530+
// Let’s count the number of coroutine-fibers that are in the YIELD state.
531+
// This state differs from the regular Suspended state in that
532+
// the Fiber has transferred control back to the parent coroutine.
533+
//
534+
zend_long fiber_coroutines_count = 0;
535+
536+
ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), value) {
537+
const zend_coroutine_t *coroutine = (zend_coroutine_t *) Z_PTR_P(value);
538+
539+
if (ZEND_COROUTINE_IS_FIBER(coroutine)
540+
&& ZEND_COROUTINE_IS_YIELD(coroutine)
541+
&& coroutine->extended_data != NULL) {
542+
fiber_coroutines_count++;
543+
}
544+
}
545+
ZEND_HASH_FOREACH_END();
546+
547+
//
548+
// If all coroutines are fiber coroutines in the SUSPENDED state,
549+
// we can simply cancel them without creating a deadlock exception.
550+
//
551+
if (fiber_coroutines_count == real_coroutines) {
552+
553+
ZEND_HASH_FOREACH_VAL(&ASYNC_G(coroutines), value) {
554+
zend_coroutine_t *coroutine = (zend_coroutine_t *) Z_PTR_P(value);
555+
556+
if (ZEND_COROUTINE_IS_FIBER(coroutine)
557+
&& ZEND_COROUTINE_IS_YIELD(coroutine)
558+
&& coroutine->extended_data != NULL) {
559+
ZEND_ASYNC_CANCEL(coroutine,
560+
async_new_exception(async_ce_cancellation_exception, "Fiber coroutine cancelled"), true);
561+
562+
if (UNEXPECTED(EG(exception) != NULL)) {
563+
return true;
564+
}
565+
}
566+
}
567+
ZEND_HASH_FOREACH_END();
568+
return false;
569+
}
570+
529571
// Create deadlock exception to be set as exit_exception
530572
zend_object *deadlock_exception = async_new_exception(async_ce_deadlock_error,
531573
"Deadlock detected: no active coroutines, %u coroutines in waiting", real_coroutines);
@@ -552,7 +594,7 @@ static bool resolve_deadlocks(void)
552594
ZEND_ASYNC_CANCEL(
553595
&coroutine->coroutine, async_new_exception(async_ce_cancellation_exception, "Deadlock detected"), true);
554596

555-
if (EG(exception) != NULL) {
597+
if (UNEXPECTED(EG(exception) != NULL)) {
556598
return true;
557599
}
558600
}

0 commit comments

Comments
 (0)