Split fiber status and flags (#7094)

Co-Authored-By: twosee <twose@qq.com>
This commit is contained in:
Aaron Piotrowski 2021-06-03 15:34:48 -05:00 committed by GitHub
parent b601acf35e
commit d2e5203865
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 40 deletions

View file

@ -321,7 +321,7 @@ static void zend_fiber_switch_to(zend_fiber *fiber)
zend_observer_fiber_switch_notify(fiber, previous);
if (UNEXPECTED(fiber->status == ZEND_FIBER_STATUS_BAILOUT)) {
if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_BAILOUT)) {
// zend_bailout() was called in the fiber, so call it again in the previous fiber or {main}.
zend_bailout();
}
@ -379,20 +379,20 @@ static void ZEND_STACK_ALIGNED zend_fiber_execute(zend_fiber_context *context)
zval_ptr_dtor(&fiber->fci.function_name);
if (EG(exception)) {
if (fiber->status == ZEND_FIBER_STATUS_SHUTDOWN) {
if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
if (EXPECTED(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))) {
zend_clear_exception();
}
} else {
fiber->status = ZEND_FIBER_STATUS_THREW;
fiber->flags = ZEND_FIBER_FLAG_THREW;
}
} else {
fiber->status = ZEND_FIBER_STATUS_RETURNED;
}
} zend_catch {
fiber->status = ZEND_FIBER_STATUS_BAILOUT;
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
} zend_end_try();
fiber->status = ZEND_FIBER_STATUS_DEAD;
zend_vm_stack_destroy();
fiber->execute_data = NULL;
fiber->stack_bottom = NULL;
@ -422,7 +422,8 @@ static void zend_fiber_object_destroy(zend_object *object)
zend_object *exception = EG(exception);
EG(exception) = NULL;
fiber->status = ZEND_FIBER_STATUS_SHUTDOWN;
fiber->status = ZEND_FIBER_STATUS_RUNNING;
fiber->flags |= ZEND_FIBER_FLAG_DESTROYED;
zend_fiber_switch_to(fiber);
@ -499,7 +500,7 @@ ZEND_API void zend_fiber_start(zend_fiber *fiber, zval *params, uint32_t param_c
zend_fiber_switch_to(fiber);
if (fiber->status & ZEND_FIBER_STATUS_FINISHED) {
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
RETURN_NULL();
}
@ -530,7 +531,7 @@ ZEND_API void zend_fiber_suspend(zval *value, zval *return_value)
RETURN_THROWS();
}
if (UNEXPECTED(fiber->status == ZEND_FIBER_STATUS_SHUTDOWN)) {
if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
RETURN_THROWS();
}
@ -549,7 +550,7 @@ ZEND_API void zend_fiber_suspend(zval *value, zval *return_value)
zend_fiber_suspend_from(fiber);
if (fiber->status == ZEND_FIBER_STATUS_SHUTDOWN) {
if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
// This occurs when the fiber is GC'ed while suspended.
zend_throw_graceful_exit();
RETURN_THROWS();
@ -599,7 +600,7 @@ ZEND_API void zend_fiber_resume(zend_fiber *fiber, zval *value, zval *return_val
zend_fiber_switch_to(fiber);
if (fiber->status & ZEND_FIBER_STATUS_FINISHED) {
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
RETURN_NULL();
}
@ -637,7 +638,7 @@ ZEND_API void zend_fiber_throw(zend_fiber *fiber, zval *exception, zval *return_
zend_fiber_switch_to(fiber);
if (fiber->status & ZEND_FIBER_STATUS_FINISHED) {
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
RETURN_NULL();
}
@ -700,7 +701,7 @@ ZEND_METHOD(Fiber, isTerminated)
fiber = (zend_fiber *) Z_OBJ_P(getThis());
RETURN_BOOL(fiber->status & ZEND_FIBER_STATUS_FINISHED);
RETURN_BOOL(fiber->status == ZEND_FIBER_STATUS_DEAD);
}
ZEND_METHOD(Fiber, getReturn)
@ -711,13 +712,15 @@ ZEND_METHOD(Fiber, getReturn)
fiber = (zend_fiber *) Z_OBJ_P(getThis());
if (fiber->status != ZEND_FIBER_STATUS_RETURNED) {
if (fiber->status != ZEND_FIBER_STATUS_DEAD || fiber->flags) {
const char *message;
if (fiber->status == ZEND_FIBER_STATUS_INIT) {
message = "The fiber has not been started";
} else if (fiber->status == ZEND_FIBER_STATUS_THREW) {
} else if (fiber->flags & ZEND_FIBER_FLAG_THREW) {
message = "The fiber threw an exception";
} else if (fiber->flags & ZEND_FIBER_FLAG_BAILOUT) {
message = "The fiber exited with a fatal error";
} else {
message = "The fiber has not returned";
}

View file

@ -25,6 +25,19 @@
BEGIN_EXTERN_C()
typedef enum {
ZEND_FIBER_STATUS_INIT,
ZEND_FIBER_STATUS_RUNNING,
ZEND_FIBER_STATUS_SUSPENDED,
ZEND_FIBER_STATUS_DEAD,
} zend_fiber_status;
typedef enum {
ZEND_FIBER_FLAG_THREW = 1 << 0,
ZEND_FIBER_FLAG_BAILOUT = 1 << 1,
ZEND_FIBER_FLAG_DESTROYED = 1 << 2,
} zend_fiber_flag;
void zend_register_fiber_ce(void);
void zend_fiber_init(void);
@ -59,8 +72,11 @@ typedef struct _zend_fiber {
/* Fiber PHP object handle. */
zend_object std;
/* Status of the fiber, one of the ZEND_FIBER_STATUS_* constants. */
zend_uchar status;
/* Status of the fiber, one of the zend_fiber_status values. */
zend_fiber_status status;
/* Flags of the fiber, bit field of the zend_fiber_flag values. */
zend_uchar flags;
/* Callback and info / cache to be used when fiber is started. */
zend_fcall_info fci;
@ -82,16 +98,6 @@ typedef struct _zend_fiber {
zval value;
} zend_fiber;
static const zend_uchar ZEND_FIBER_STATUS_INIT = 0x0;
static const zend_uchar ZEND_FIBER_STATUS_SUSPENDED = 0x1;
static const zend_uchar ZEND_FIBER_STATUS_RUNNING = 0x2;
static const zend_uchar ZEND_FIBER_STATUS_RETURNED = 0x4;
static const zend_uchar ZEND_FIBER_STATUS_THREW = 0x8;
static const zend_uchar ZEND_FIBER_STATUS_SHUTDOWN = 0x10;
static const zend_uchar ZEND_FIBER_STATUS_BAILOUT = 0x20;
static const zend_uchar ZEND_FIBER_STATUS_FINISHED = 0x2c;
/* These functions create and manipulate a Fiber object, allowing any internal function to start, resume, or suspend a fiber. */
ZEND_API zend_fiber *zend_fiber_create(const zend_fcall_info *fci, const zend_fcall_info_cache *fci_cache);
ZEND_API void zend_fiber_start(zend_fiber *fiber, zval *params, uint32_t param_count, zend_array *named_params, zval *return_value);

View file

@ -6873,7 +6873,7 @@ ZEND_METHOD(ReflectionFiber, getFiber)
}
#define REFLECTION_CHECK_VALID_FIBER(fiber) do { \
if (fiber == NULL || fiber->status == ZEND_FIBER_STATUS_INIT || fiber->status & ZEND_FIBER_STATUS_FINISHED) { \
if (fiber == NULL || fiber->status == ZEND_FIBER_STATUS_INIT || fiber->status == ZEND_FIBER_STATUS_DEAD) { \
zend_throw_error(NULL, "Cannot fetch information from a fiber that has not been started or is terminated"); \
RETURN_THROWS(); \
} \
@ -6948,7 +6948,7 @@ ZEND_METHOD(ReflectionFiber, getCallable)
ZEND_PARSE_PARAMETERS_NONE();
if (fiber == NULL || fiber->status & ZEND_FIBER_STATUS_FINISHED) {
if (fiber == NULL || fiber->status == ZEND_FIBER_STATUS_DEAD) {
zend_throw_error(NULL, "Cannot fetch the callable from a fiber that has terminated"); \
RETURN_THROWS();
}

View file

@ -425,9 +425,11 @@ static void fiber_enter_observer(zend_fiber *from, zend_fiber *to)
if (to->status == ZEND_FIBER_STATUS_INIT) {
php_printf("<init '%p'>\n", to);
} else if (to->status == ZEND_FIBER_STATUS_RUNNING && (!from || from->status == ZEND_FIBER_STATUS_RUNNING)) {
php_printf("<resume '%p'>\n", to);
} else if (to->status == ZEND_FIBER_STATUS_SHUTDOWN) {
if (to->flags & ZEND_FIBER_FLAG_DESTROYED) {
php_printf("<destroying '%p'>\n", to);
} else if (to->status != ZEND_FIBER_STATUS_DEAD) {
php_printf("<resume '%p'>\n", to);
}
}
}
}
@ -439,12 +441,14 @@ static void fiber_suspend_observer(zend_fiber *from, zend_fiber *to)
if (from) {
if (from->status == ZEND_FIBER_STATUS_SUSPENDED) {
php_printf("<suspend '%p'>\n", from);
} else if (from->status == ZEND_FIBER_STATUS_RETURNED) {
php_printf("<returned '%p'>\n", from);
} else if (from->status == ZEND_FIBER_STATUS_THREW) {
} else if (from->status == ZEND_FIBER_STATUS_DEAD) {
if (from->flags & ZEND_FIBER_FLAG_THREW) {
php_printf("<threw '%p'>\n", from);
} else if (from->status == ZEND_FIBER_STATUS_SHUTDOWN) {
} else if (from->flags & ZEND_FIBER_FLAG_DESTROYED) {
php_printf("<destroyed '%p'>\n", from);
} else {
php_printf("<returned '%p'>\n", from);
}
}
}
}

View file

@ -44,9 +44,7 @@ $fiber->resume();
<destroying '%s'>
<!-- switching from fiber %s to %s -->
<destroying '%s'>
<destroyed '%s'>
<!-- switching from fiber %s to %s -->
<destroying '%s'>
<destroyed '%s'>
<!-- switching from fiber %s to 0 -->
<destroyed '%s'>