@@ -172,20 +172,19 @@ static bool execute_next_coroutine(zend_fiber_transfer *transfer)
172172 return false;
173173 }
174174
175- if (UNEXPECTED (coroutine -> waker == NULL )) {
176- coroutine -> event .dispose (& coroutine -> event );
177- return true;
178- }
179-
180175 zend_async_waker_t * waker = coroutine -> waker ;
181176
182- if (UNEXPECTED (waker -> status == ZEND_ASYNC_WAKER_IGNORED )) {
177+ if (UNEXPECTED (waker == NULL || waker -> status == ZEND_ASYNC_WAKER_IGNORED )) {
183178
184179 //
185180 // This state triggers if the fiber has never been started;
186181 // in this case, it is deallocated differently than usual.
187182 // Finalizing handlers are called. Memory is freed in the correct order!
188183 //
184+ if (ZEND_COROUTINE_IS_CANCELLED (coroutine )) {
185+ async_coroutine_finalize (NULL , async_coroutine );
186+ }
187+
189188 coroutine -> event .dispose (& coroutine -> event );
190189 return true;
191190 }
@@ -380,6 +379,9 @@ static void cancel_queued_coroutines(void)
380379 if (((async_coroutine_t * ) coroutine )-> context .status == ZEND_FIBER_STATUS_INIT ) {
381380 // No need to cancel the fiber if it has not been started.
382381 coroutine -> waker -> status = ZEND_ASYNC_WAKER_IGNORED ;
382+ ZEND_COROUTINE_SET_CANCELLED (coroutine );
383+ coroutine -> exception = cancellation_exception ;
384+ GC_ADDREF (cancellation_exception );
383385 } else {
384386 ZEND_ASYNC_CANCEL (coroutine , cancellation_exception , false);
385387 }
@@ -744,7 +746,18 @@ void async_scheduler_coroutine_suspend(zend_fiber_transfer *transfer)
744746 //
745747 if (transfer == NULL && ZEND_ASYNC_CURRENT_COROUTINE != NULL && ZEND_ASYNC_CURRENT_COROUTINE -> waker != NULL ) {
746748 async_scheduler_start_waker_events (ZEND_ASYNC_CURRENT_COROUTINE -> waker );
747- TRY_HANDLE_SUSPEND_EXCEPTION ();
749+
750+ // If an exception occurs during the startup of the Waker object,
751+ // that exception belongs to the current coroutine,
752+ // which means we have the right to immediately return to the point from which we were called.
753+ if (UNEXPECTED (EG (exception ) != NULL )) {
754+ // Before returning, We are required to properly destroy the Waker object.
755+ zend_exception_save ();
756+ async_scheduler_stop_waker_events (ZEND_ASYNC_CURRENT_COROUTINE -> waker );
757+ zend_async_waker_destroy (ZEND_ASYNC_CURRENT_COROUTINE );
758+ zend_exception_restore ();
759+ return ;
760+ }
748761 }
749762
750763 //
0 commit comments