Skip to content

Commit 95b12f7

Browse files
committed
* fix zend_async_waker_callback_resolve. The method now automatically captures the exception, marking it as handled in another coroutine.
1 parent 152c877 commit 95b12f7

File tree

2 files changed

+17
-5
lines changed

2 files changed

+17
-5
lines changed

Zend/zend_async_API.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,14 @@ ZEND_API void zend_async_waker_callback_resolve(
547547
}
548548
}
549549

550+
if (exception != NULL) {
551+
//
552+
// This handler always captures the exception as handled because it passes it to another coroutine.
553+
// As a result, the exception will not propagate further.
554+
//
555+
ZEND_ASYNC_EVENT_SET_EXCEPTION_HANDLED(event);
556+
}
557+
550558
ZEND_ASYNC_RESUME_WITH_ERROR(coroutine, exception, false);
551559
}
552560

Zend/zend_async_API.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,13 +311,15 @@ struct _zend_async_event_s {
311311
#define ZEND_ASYNC_EVENT_F_ZVAL_RESULT (1u << 3)
312312
#define ZEND_ASYNC_EVENT_F_ZEND_OBJ (1u << 4) /* event is a zend object */
313313
#define ZEND_ASYNC_EVENT_F_NO_FREE_MEMORY (1u << 5) /* event will not free memory in dispose handler */
314+
#define ZEND_ASYNC_EVENT_F_EXCEPTION_HANDLED (1u << 6) /* exception has been caught and processed */
314315

315316
#define ZEND_ASYNC_EVENT_IS_CLOSED(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_CLOSED) != 0)
316317
#define ZEND_ASYNC_EVENT_WILL_RESULT_USED(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_RESULT_USED) != 0)
317318
#define ZEND_ASYNC_EVENT_WILL_EXC_CAUGHT(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_EXC_CAUGHT) != 0)
318319
#define ZEND_ASYNC_EVENT_WILL_ZVAL_RESULT(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_ZVAL_RESULT) != 0)
319320
#define ZEND_ASYNC_EVENT_IS_ZEND_OBJ(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_ZEND_OBJ) != 0)
320321
#define ZEND_ASYNC_EVENT_IS_NO_FREE_MEMORY(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_NO_FREE_MEMORY) != 0)
322+
#define ZEND_ASYNC_EVENT_IS_EXCEPTION_HANDLED(ev) (((ev)->flags & ZEND_ASYNC_EVENT_F_EXCEPTION_HANDLED) != 0)
321323

322324
#define ZEND_ASYNC_EVENT_SET_CLOSED(ev) ((ev)->flags |= ZEND_ASYNC_EVENT_F_CLOSED)
323325
#define ZEND_ASYNC_EVENT_CLR_CLOSED(ev) ((ev)->flags &= ~ZEND_ASYNC_EVENT_F_CLOSED)
@@ -336,6 +338,9 @@ struct _zend_async_event_s {
336338

337339
#define ZEND_ASYNC_EVENT_SET_NO_FREE_MEMORY(ev) ((ev)->flags |= ZEND_ASYNC_EVENT_F_NO_FREE_MEMORY)
338340

341+
#define ZEND_ASYNC_EVENT_SET_EXCEPTION_HANDLED(ev) ((ev)->flags |= ZEND_ASYNC_EVENT_F_EXCEPTION_HANDLED)
342+
#define ZEND_ASYNC_EVENT_CLR_EXCEPTION_HANDLED(ev) ((ev)->flags &= ~ZEND_ASYNC_EVENT_F_EXCEPTION_HANDLED)
343+
339344
// Convert awaitable Zend object to zend_async_event_t pointer
340345
#define ZEND_ASYNC_OBJECT_TO_EVENT(obj) ((zend_async_event_t *)((char *)(obj) - (obj)->handlers->offset))
341346
#define ZEND_ASYNC_EVENT_TO_OBJECT(event) ((zend_object *)((char *)(event) + (event)->zend_object_offset))
@@ -728,25 +733,24 @@ struct _zend_coroutine_s {
728733
#define ZEND_COROUTINE_F_CANCELLED (1u << 11) /* coroutine is cancelled */
729734
#define ZEND_COROUTINE_F_ZOMBIE (1u << 12) /* coroutine is a zombie */
730735
#define ZEND_COROUTINE_F_PROTECTED (1u << 13) /* coroutine is protected */
731-
#define ZEND_COROUTINE_F_EXCEPTION_HANDLED (1u << 14) /* exception has been caught and processed */
732-
#define ZEND_COROUTINE_F_MAIN (1u << 15) /* coroutine is a main coroutine */
736+
#define ZEND_COROUTINE_F_MAIN (1u << 14) /* coroutine is a main coroutine */
733737

734738
#define ZEND_COROUTINE_IS_ZOMBIE(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_ZOMBIE) != 0)
735739
#define ZEND_COROUTINE_SET_ZOMBIE(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_ZOMBIE)
736740
#define ZEND_COROUTINE_IS_STARTED(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_STARTED) != 0)
737741
#define ZEND_COROUTINE_IS_CANCELLED(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_CANCELLED) != 0)
738742
#define ZEND_COROUTINE_IS_FINISHED(coroutine) (((coroutine)->event.flags & ZEND_ASYNC_EVENT_F_CLOSED) != 0)
739743
#define ZEND_COROUTINE_IS_PROTECTED(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_PROTECTED) != 0)
740-
#define ZEND_COROUTINE_IS_EXCEPTION_HANDLED(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_EXCEPTION_HANDLED) != 0)
744+
#define ZEND_COROUTINE_IS_EXCEPTION_HANDLED(coroutine) ZEND_ASYNC_EVENT_IS_EXCEPTION_HANDLED(&(coroutine)->event)
741745
#define ZEND_COROUTINE_IS_MAIN(coroutine) (((coroutine)->event.flags & ZEND_COROUTINE_F_MAIN) != 0)
742746
#define ZEND_COROUTINE_SET_STARTED(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_STARTED)
743747
#define ZEND_COROUTINE_SET_CANCELLED(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_CANCELLED)
744748
#define ZEND_COROUTINE_SET_FINISHED(coroutine) ((coroutine)->event.flags |= ZEND_ASYNC_EVENT_F_CLOSED)
745749
#define ZEND_COROUTINE_SET_PROTECTED(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_PROTECTED)
746750
#define ZEND_COROUTINE_SET_MAIN(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_MAIN)
747751
#define ZEND_COROUTINE_CLR_PROTECTED(coroutine) ((coroutine)->event.flags &= ~ZEND_COROUTINE_F_PROTECTED)
748-
#define ZEND_COROUTINE_SET_EXCEPTION_HANDLED(coroutine) ((coroutine)->event.flags |= ZEND_COROUTINE_F_EXCEPTION_HANDLED)
749-
#define ZEND_COROUTINE_CLR_EXCEPTION_HANDLED(coroutine) ((coroutine)->event.flags &= ~ZEND_COROUTINE_F_EXCEPTION_HANDLED)
752+
#define ZEND_COROUTINE_SET_EXCEPTION_HANDLED(coroutine) ZEND_ASYNC_EVENT_SET_EXCEPTION_HANDLED(&(coroutine)->event)
753+
#define ZEND_COROUTINE_CLR_EXCEPTION_HANDLED(coroutine) ZEND_ASYNC_EVENT_CLR_EXCEPTION_HANDLED(&(coroutine)->event)
750754

751755
static zend_always_inline zend_string *zend_coroutine_callable_name(const zend_coroutine_t *coroutine)
752756
{

0 commit comments

Comments
 (0)