Skip to content

Commit 66442a5

Browse files
authored
Allow creating Graceful/UnwindExit and use when destroying a fiber (#7174)
Direct creation of GracefulExit allows the the special exception object to be transfered and thrown into a destroyed fiber using the same path as any other exception thrown into a fiber instead of needing to check for a flag.
1 parent 773e9ba commit 66442a5

File tree

3 files changed

+20
-10
lines changed

3 files changed

+20
-10
lines changed

Zend/zend_exceptions.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,18 +1002,28 @@ ZEND_API ZEND_COLD void zend_throw_exception_object(zval *exception) /* {{{ */
10021002
}
10031003
/* }}} */
10041004

1005+
ZEND_API ZEND_COLD zend_object *zend_create_unwind_exit(void)
1006+
{
1007+
return zend_objects_new(&zend_ce_unwind_exit);
1008+
}
1009+
1010+
ZEND_API ZEND_COLD zend_object *zend_create_graceful_exit(void)
1011+
{
1012+
return zend_objects_new(&zend_ce_graceful_exit);
1013+
}
1014+
10051015
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void)
10061016
{
10071017
ZEND_ASSERT(!EG(exception));
1008-
EG(exception) = zend_objects_new(&zend_ce_unwind_exit);
1018+
EG(exception) = zend_create_unwind_exit();
10091019
EG(opline_before_exception) = EG(current_execute_data)->opline;
10101020
EG(current_execute_data)->opline = EG(exception_op);
10111021
}
10121022

10131023
ZEND_API ZEND_COLD void zend_throw_graceful_exit(void)
10141024
{
10151025
ZEND_ASSERT(!EG(exception));
1016-
EG(exception) = zend_objects_new(&zend_ce_graceful_exit);
1026+
EG(exception) = zend_create_graceful_exit();
10171027
EG(opline_before_exception) = EG(current_execute_data)->opline;
10181028
EG(current_execute_data)->opline = EG(exception_op);
10191029
}

Zend/zend_exceptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *exception, int
7171
ZEND_NORETURN void zend_exception_uncaught_error(const char *prefix, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
7272
ZEND_API zend_string *zend_trace_to_string(HashTable *trace, bool include_main);
7373

74+
ZEND_API ZEND_COLD zend_object *zend_create_unwind_exit(void);
75+
ZEND_API ZEND_COLD zend_object *zend_create_graceful_exit(void);
7476
ZEND_API ZEND_COLD void zend_throw_unwind_exit(void);
7577
ZEND_API ZEND_COLD void zend_throw_graceful_exit(void);
7678
ZEND_API bool zend_is_unwind_exit(const zend_object *ex);

Zend/zend_fibers.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -539,9 +539,14 @@ static void zend_fiber_object_destroy(zend_object *object)
539539
zend_object *exception = EG(exception);
540540
EG(exception) = NULL;
541541

542+
zval graceful_exit;
543+
ZVAL_OBJ(&graceful_exit, zend_create_graceful_exit());
544+
542545
fiber->flags |= ZEND_FIBER_FLAG_DESTROYED;
543546

544-
zend_fiber_transfer transfer = zend_fiber_resume(fiber, NULL, false);
547+
zend_fiber_transfer transfer = zend_fiber_resume(fiber, &graceful_exit, true);
548+
549+
zval_ptr_dtor(&graceful_exit);
545550

546551
if (transfer.flags & ZEND_FIBER_TRANSFER_FLAG_ERROR) {
547552
EG(exception) = Z_OBJ(transfer.value);
@@ -659,13 +664,6 @@ ZEND_METHOD(Fiber, suspend)
659664

660665
zend_fiber_transfer transfer = zend_fiber_suspend(fiber, value);
661666

662-
if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
663-
// This occurs when the fiber is GC'ed while suspended.
664-
zval_ptr_dtor(&transfer.value);
665-
zend_throw_graceful_exit();
666-
RETURN_THROWS();
667-
}
668-
669667
zend_fiber_delegate_transfer_result(&transfer, INTERNAL_FUNCTION_PARAM_PASSTHRU);
670668
}
671669

0 commit comments

Comments
 (0)