Skip to content

Commit 9537c42

Browse files
committed
% Added code to catch exceptions in the main coroutine. The exception is now passed to the main coroutine’s finalize method instead of being displayed on screen.
* Fixed an issue with correctly passing the exception into the coroutine.
1 parent 4cff86f commit 9537c42

File tree

3 files changed

+26
-10
lines changed

3 files changed

+26
-10
lines changed

Zend/zend.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
#include "Optimizer/zend_optimizer.h"
4242
#include "php.h"
4343
#include "php_globals.h"
44+
#ifdef PHP_ASYNC_API
45+
#include "zend_async_API.h"
46+
#endif
4447

4548
// FIXME: Breaks the declaration of the function below
4649
#undef zenderror
@@ -1946,9 +1949,18 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl
19461949
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
19471950
zend_user_exception_handler();
19481951
}
1952+
#ifdef PHP_ASYNC_API
1953+
// If we are inside a coroutine,
1954+
// we do not call the final error handler,
1955+
// as the exception will be handled higher up in the method ZEND_ASYNC_RUN_SCHEDULER_AFTER_MAIN
1956+
if (false == ZEND_ASYNC_CURRENT_COROUTINE && EG(exception)) {
1957+
ret = zend_exception_error(EG(exception), E_ERROR);
1958+
}
1959+
#else
19491960
if (EG(exception)) {
19501961
ret = zend_exception_error(EG(exception), E_ERROR);
19511962
}
1963+
#endif
19521964
}
19531965
zend_destroy_static_vars(op_array);
19541966
destroy_op_array(op_array);

Zend/zend_async_API.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -559,16 +559,9 @@ ZEND_API void zend_async_waker_callback_cancel(
559559
if (UNEXPECTED(exception != NULL)) {
560560
ZEND_ASYNC_RESUME_WITH_ERROR(coroutine, exception, false);
561561
} else {
562-
563-
if (result == NULL) {
564-
exception = zend_async_new_exception(
565-
ZEND_ASYNC_EXCEPTION_CANCELLATION, "Operation has been cancelled"
566-
);
567-
} else {
568-
exception = result;
569-
}
570-
571-
ZEND_ASYNC_RESUME_WITH_ERROR(coroutine, exception, false);
562+
ZEND_ASYNC_RESUME_WITH_ERROR(coroutine, zend_async_new_exception(
563+
ZEND_ASYNC_EXCEPTION_CANCELLATION, "Operation has been cancelled"
564+
), true);
572565
}
573566
}
574567

Zend/zend_async_API.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ typedef void (*zend_async_event_callback_fn)
135135
typedef void (*zend_async_event_callback_dispose_fn)(zend_async_event_callback_t *callback, zend_async_event_t * event);
136136
typedef void (*zend_async_event_add_callback_t)(zend_async_event_t *event, zend_async_event_callback_t *callback);
137137
typedef void (*zend_async_event_del_callback_t)(zend_async_event_t *event, zend_async_event_callback_t *callback);
138+
typedef bool (*zend_async_event_callbacks_notify_t)(zend_async_event_t *event, void *result, zend_object *exception);
138139
typedef void (*zend_async_event_start_t) (zend_async_event_t *event);
139140
typedef void (*zend_async_event_stop_t) (zend_async_event_t *event);
140141
typedef void (*zend_async_event_dispose_t) (zend_async_event_t *event);
@@ -291,6 +292,11 @@ struct _zend_async_event_s {
291292
/* Methods */
292293
zend_async_event_add_callback_t add_callback;
293294
zend_async_event_del_callback_t del_callback;
295+
/*
296+
* Handler that is invoked before all event listeners are notified.
297+
* May be NULL.
298+
*/
299+
zend_async_event_callbacks_notify_t before_notify;
294300
zend_async_event_start_t start;
295301
zend_async_event_stop_t stop;
296302
zend_async_event_dispose_t dispose;
@@ -404,6 +410,11 @@ zend_async_callbacks_remove(zend_async_event_t *event, const zend_async_event_ca
404410
static zend_always_inline void
405411
zend_async_callbacks_notify(zend_async_event_t *event, void *result, zend_object *exception)
406412
{
413+
// If pre-notify returns false, we stop notifying callbacks
414+
if (event->before_notify != NULL && false == event->before_notify(event, result, exception)) {
415+
return;
416+
}
417+
407418
if (event->callbacks.data == NULL) {
408419
return;
409420
}

0 commit comments

Comments
 (0)