@@ -406,7 +406,7 @@ ZEND_API zend_async_event_callback_t * zend_async_event_callback_new(zend_async_
406406 return event_callback ;
407407}
408408
409- static void coroutine_event_callback_dispose (zend_async_event_callback_t * callback , zend_async_event_t * event );
409+ void coroutine_event_callback_dispose (zend_async_event_callback_t * callback , zend_async_event_t * event );
410410
411411ZEND_API zend_coroutine_event_callback_t * zend_async_coroutine_callback_new (
412412 zend_coroutine_t * coroutine , zend_async_event_callback_fn callback , size_t size
@@ -552,14 +552,18 @@ static void coroutine_event_callback_dispose(zend_async_event_callback_t *callba
552552
553553 callback -> ref_count = 0 ;
554554
555- zend_async_waker_t * waker = ((zend_coroutine_event_callback_t * ) callback )-> coroutine -> waker ;
555+ const zend_coroutine_t * coroutine = ((zend_coroutine_event_callback_t * ) callback )-> coroutine ;
556556
557- if (event != NULL && waker != NULL ) {
558- // remove the event from the waker
559- zend_hash_index_del (& waker -> events , (zend_ulong )event );
557+ if (EXPECTED (coroutine != NULL )) {
558+ zend_async_waker_t * waker = coroutine -> waker ;
560559
561- if (waker -> triggered_events != NULL ) {
562- zend_hash_index_del (waker -> triggered_events , (zend_ulong )event );
560+ if (event != NULL && waker != NULL ) {
561+ // remove the event from the waker
562+ zend_hash_index_del (& waker -> events , (zend_ulong )event );
563+
564+ if (waker -> triggered_events != NULL ) {
565+ zend_hash_index_del (waker -> triggered_events , (zend_ulong )event );
566+ }
563567 }
564568 }
565569
@@ -582,6 +586,15 @@ ZEND_API void zend_async_waker_add_triggered_event(zend_coroutine_t *coroutine,
582586 }
583587}
584588
589+ ZEND_API bool zend_async_waker_is_event_exists (zend_coroutine_t * coroutine , zend_async_event_t * event )
590+ {
591+ if (UNEXPECTED (coroutine -> waker == NULL )) {
592+ return false;
593+ }
594+
595+ return zend_hash_index_find (& coroutine -> waker -> events , (zend_ulong )event ) != NULL ;
596+ }
597+
585598ZEND_API void zend_async_resume_when (
586599 zend_coroutine_t * coroutine ,
587600 zend_async_event_t * event ,
@@ -590,6 +603,8 @@ ZEND_API void zend_async_resume_when(
590603 zend_coroutine_event_callback_t * event_callback
591604 )
592605{
606+ bool locally_allocated_callback = false;
607+
593608 if (UNEXPECTED (ZEND_ASYNC_EVENT_IS_CLOSED (event ))) {
594609 zend_throw_error (NULL , "The event cannot be used after it has been terminated" );
595610 return ;
@@ -610,6 +625,7 @@ ZEND_API void zend_async_resume_when(
610625 event_callback -> base .ref_count = 1 ;
611626 event_callback -> base .callback = callback ;
612627 event_callback -> base .dispose = coroutine_event_callback_dispose ;
628+ locally_allocated_callback = true;
613629 }
614630
615631 // Set up the default dispose function if not set
@@ -627,6 +643,10 @@ ZEND_API void zend_async_resume_when(
627643 event -> add_callback (event , & event_callback -> base );
628644
629645 if (UNEXPECTED (EG (exception ) != NULL )) {
646+ if (locally_allocated_callback ) {
647+ event_callback -> base .dispose (& event_callback -> base , event );
648+ }
649+
630650 if (trans_event ) {
631651 event -> dispose (event );
632652 }
@@ -640,7 +660,18 @@ ZEND_API void zend_async_resume_when(
640660 trigger -> callback = & event_callback -> base ;
641661
642662 if (UNEXPECTED (zend_hash_index_add_ptr (& coroutine -> waker -> events , (zend_ulong )event , trigger ) == NULL )) {
643- zend_throw_error (NULL , "Failed to add event to the waker" );
663+ efree (trigger );
664+
665+ if (locally_allocated_callback ) {
666+ event_callback -> base .dispose (& event_callback -> base , event );
667+ }
668+
669+ if (trans_event ) {
670+ event -> dispose (event );
671+ }
672+
673+ zend_throw_error (NULL , "Failed to add event to the waker: maybe event already exists" );
674+
644675 return ;
645676 }
646677 }
0 commit comments