@@ -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