Skip to content

Commit

Permalink
Remove fiber context embedding
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Jun 14, 2021
1 parent fdc2274 commit 859524c
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 66 deletions.
48 changes: 23 additions & 25 deletions Zend/zend_fibers.c
Expand Up @@ -392,10 +392,10 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
zval_ptr_dtor(&fiber->fci.function_name);

if (EG(exception)) {
if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)
if (!(fiber->context.flags & ZEND_FIBER_FLAG_DESTROYED)
|| !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))
) {
fiber->flags |= ZEND_FIBER_FLAG_THREW;
fiber->context.flags |= ZEND_FIBER_FLAG_THREW;
transfer->flags = ZEND_FIBER_TRANSFER_FLAG_ERROR;

ZVAL_OBJ_COPY(&transfer->value, EG(exception));
Expand All @@ -406,7 +406,7 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
ZVAL_COPY(&transfer->value, &fiber->result);
}
} zend_catch {
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
fiber->context.flags |= ZEND_FIBER_FLAG_BAILOUT;
} zend_end_try();

transfer->context = fiber->caller;
Expand All @@ -427,7 +427,7 @@ static zend_always_inline void delegate_transfer_result(
RETURN_THROWS();
}

if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
if (fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
zval_ptr_dtor(&transfer->value);
RETURN_NULL();
}
Expand Down Expand Up @@ -496,14 +496,14 @@ static void zend_fiber_object_destroy(zend_object *object)
{
zend_fiber *fiber = (zend_fiber *) object;

if (fiber->status != ZEND_FIBER_STATUS_SUSPENDED) {
if (fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED) {
return;
}

zend_object *exception = EG(exception);
EG(exception) = NULL;

fiber->flags |= ZEND_FIBER_FLAG_DESTROYED;
fiber->context.flags |= ZEND_FIBER_FLAG_DESTROYED;

zend_fiber_transfer transfer = zend_fiber_resume(fiber, NULL, false);

Expand All @@ -530,7 +530,7 @@ static void zend_fiber_object_free(zend_object *object)
{
zend_fiber *fiber = (zend_fiber *) object;

if (fiber->status == ZEND_FIBER_STATUS_INIT) {
if (fiber->context.status == ZEND_FIBER_STATUS_INIT) {
// Fiber was never started, so we need to release the reference to the callback.
zval_ptr_dtor(&fiber->fci.function_name);
}
Expand Down Expand Up @@ -568,7 +568,7 @@ ZEND_METHOD(Fiber, start)
RETURN_THROWS();
}

if (fiber->status != ZEND_FIBER_STATUS_INIT) {
if (fiber->context.status != ZEND_FIBER_STATUS_INIT) {
zend_throw_error(zend_ce_fiber_error, "Cannot start a fiber that has already been started");
RETURN_THROWS();
}
Expand All @@ -577,13 +577,11 @@ ZEND_METHOD(Fiber, start)
fiber->fci.param_count = param_count;
fiber->fci.named_params = named_params;

zend_fiber_context *context = zend_fiber_get_context(fiber);

if (!zend_fiber_init_context(context, zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) {
if (!zend_fiber_init_context(&fiber->context, zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) {
RETURN_THROWS();
}

fiber->previous = context;
fiber->previous = &fiber->context;

zend_fiber_transfer transfer = zend_fiber_resume(fiber, NULL, false);

Expand All @@ -606,7 +604,7 @@ ZEND_METHOD(Fiber, suspend)
RETURN_THROWS();
}

if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) {
if (UNEXPECTED(fiber->context.flags & ZEND_FIBER_FLAG_DESTROYED)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
RETURN_THROWS();
}
Expand All @@ -616,14 +614,14 @@ ZEND_METHOD(Fiber, suspend)
RETURN_THROWS();
}

ZEND_ASSERT(fiber->status == ZEND_FIBER_STATUS_RUNNING || fiber->status == ZEND_FIBER_STATUS_SUSPENDED);
ZEND_ASSERT(fiber->context.status == ZEND_FIBER_STATUS_RUNNING || fiber->context.status == ZEND_FIBER_STATUS_SUSPENDED);

fiber->execute_data = EG(current_execute_data);
fiber->stack_bottom->prev_execute_data = NULL;

zend_fiber_transfer transfer = zend_fiber_suspend(fiber, value);

if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
if (fiber->context.flags & ZEND_FIBER_FLAG_DESTROYED) {
// This occurs when the fiber is GC'ed while suspended.
zval_ptr_dtor(&transfer.value);
zend_throw_graceful_exit();
Expand All @@ -650,7 +648,7 @@ ZEND_METHOD(Fiber, resume)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

if (UNEXPECTED(fiber->status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
if (UNEXPECTED(fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
zend_throw_error(zend_ce_fiber_error, "Cannot resume a fiber that is not suspended");
RETURN_THROWS();
}
Expand Down Expand Up @@ -678,7 +676,7 @@ ZEND_METHOD(Fiber, throw)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

if (UNEXPECTED(fiber->status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
if (UNEXPECTED(fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
zend_throw_error(zend_ce_fiber_error, "Cannot resume a fiber that is not suspended");
RETURN_THROWS();
}
Expand All @@ -698,7 +696,7 @@ ZEND_METHOD(Fiber, isStarted)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

RETURN_BOOL(fiber->status != ZEND_FIBER_STATUS_INIT);
RETURN_BOOL(fiber->context.status != ZEND_FIBER_STATUS_INIT);
}

ZEND_METHOD(Fiber, isSuspended)
Expand All @@ -709,7 +707,7 @@ ZEND_METHOD(Fiber, isSuspended)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

RETURN_BOOL(fiber->status == ZEND_FIBER_STATUS_SUSPENDED && fiber->caller == NULL);
RETURN_BOOL(fiber->context.status == ZEND_FIBER_STATUS_SUSPENDED && fiber->caller == NULL);
}

ZEND_METHOD(Fiber, isRunning)
Expand All @@ -720,7 +718,7 @@ ZEND_METHOD(Fiber, isRunning)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

RETURN_BOOL(fiber->status == ZEND_FIBER_STATUS_RUNNING || fiber->caller != NULL);
RETURN_BOOL(fiber->context.status == ZEND_FIBER_STATUS_RUNNING || fiber->caller != NULL);
}

ZEND_METHOD(Fiber, isTerminated)
Expand All @@ -731,7 +729,7 @@ ZEND_METHOD(Fiber, isTerminated)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

RETURN_BOOL(fiber->status == ZEND_FIBER_STATUS_DEAD);
RETURN_BOOL(fiber->context.status == ZEND_FIBER_STATUS_DEAD);
}

ZEND_METHOD(Fiber, getReturn)
Expand All @@ -743,15 +741,15 @@ ZEND_METHOD(Fiber, getReturn)

fiber = (zend_fiber *) Z_OBJ_P(getThis());

if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
if (fiber->flags & ZEND_FIBER_FLAG_THREW) {
if (fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
if (fiber->context.flags & ZEND_FIBER_FLAG_THREW) {
message = "The fiber threw an exception";
} else if (fiber->flags & ZEND_FIBER_FLAG_BAILOUT) {
} else if (fiber->context.flags & ZEND_FIBER_FLAG_BAILOUT) {
message = "The fiber exited with a fatal error";
} else {
RETURN_COPY(&fiber->result);
}
} else if (fiber->status == ZEND_FIBER_STATUS_INIT) {
} else if (fiber->context.status == ZEND_FIBER_STATUS_INIT) {
message = "The fiber has not been started";
} else {
message = "The fiber has not returned";
Expand Down
28 changes: 11 additions & 17 deletions Zend/zend_fibers.h
Expand Up @@ -74,20 +74,15 @@ typedef struct _zend_fiber_transfer {
* and (optional) data before they return. */
typedef void (*zend_fiber_coroutine)(zend_fiber_transfer *transfer);

/* Defined as a macro to allow anonymous embedding. */
#define ZEND_FIBER_CONTEXT_FIELDS \
/* Handle to fiber state as needed by boost.context */ \
void *handle; \
/* Pointer that identifies the fiber type. */ \
void *kind; \
zend_fiber_coroutine function; \
zend_fiber_stack *stack; \
zend_fiber_status status; \
uint8_t flags

/* Standalone context (used primarily as pointer type). */
struct _zend_fiber_context {
ZEND_FIBER_CONTEXT_FIELDS;
/* Handle to fiber state as needed by boost.context */
void *handle;
/* Pointer that identifies the fiber type. */
void *kind;
zend_fiber_coroutine function;
zend_fiber_stack *stack;
zend_fiber_status status;
uint8_t flags;
};

/* Zend VM state that needs to be captured / restored during fiber context switch. */
Expand All @@ -107,8 +102,7 @@ struct _zend_fiber {
/* PHP object handle. */
zend_object std;

/* Fiber context fields (embedded to avoid memory allocation). */
ZEND_FIBER_CONTEXT_FIELDS;
zend_fiber_context context;

/* Fiber that resumed us. */
zend_fiber_context *caller;
Expand Down Expand Up @@ -141,12 +135,12 @@ static zend_always_inline zend_fiber *zend_fiber_from_context(zend_fiber_context
{
ZEND_ASSERT(context->kind == zend_ce_fiber && "Fiber context does not belong to a Zend fiber");

return (zend_fiber *)(((char *) context) - XtOffsetOf(zend_fiber, handle));
return (zend_fiber *)(((char *) context) - XtOffsetOf(zend_fiber, context));
}

static zend_always_inline zend_fiber_context *zend_fiber_get_context(zend_fiber *fiber)
{
return (zend_fiber_context *) &fiber->handle;
return &fiber->context;
}

static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *state)
Expand Down
4 changes: 2 additions & 2 deletions ext/reflection/php_reflection.c
Expand Up @@ -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_DEAD) { \
if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_INIT || fiber->context.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(); \
} \
Expand Down Expand Up @@ -6948,7 +6948,7 @@ ZEND_METHOD(ReflectionFiber, getCallable)

ZEND_PARSE_PARAMETERS_NONE();

if (fiber == NULL || fiber->status == ZEND_FIBER_STATUS_DEAD) {
if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
zend_throw_error(NULL, "Cannot fetch the callable from a fiber that has terminated"); \
RETURN_THROWS();
}
Expand Down
35 changes: 14 additions & 21 deletions ext/zend_test/fiber.c
Expand Up @@ -23,11 +23,6 @@
static zend_class_entry *zend_test_fiber_class;
static zend_object_handlers zend_test_fiber_handlers;

static zend_always_inline zend_fiber_context *zend_test_fiber_get_context(zend_test_fiber *fiber)
{
return (zend_fiber_context *) &fiber->handle;
}

static zend_fiber_transfer zend_test_fiber_switch_to(zend_fiber_context *context, zval *value, bool exception)
{
zend_fiber_transfer transfer = {
Expand Down Expand Up @@ -102,10 +97,10 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran
zval_ptr_dtor(&fiber->fci.function_name);

if (EG(exception)) {
if (!(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)
if (!(fiber->context.flags & ZEND_FIBER_FLAG_DESTROYED)
|| !(zend_is_graceful_exit(EG(exception)) || zend_is_unwind_exit(EG(exception)))
) {
fiber->flags |= ZEND_FIBER_FLAG_THREW;
fiber->context.flags |= ZEND_FIBER_FLAG_THREW;
transfer->flags = ZEND_FIBER_TRANSFER_FLAG_ERROR;

ZVAL_OBJ_COPY(&transfer->value, EG(exception));
Expand All @@ -117,13 +112,13 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran
ZVAL_COPY(&transfer->value, &fiber->result);
}
} zend_catch {
fiber->flags |= ZEND_FIBER_FLAG_BAILOUT;
fiber->context.flags |= ZEND_FIBER_FLAG_BAILOUT;
} zend_end_try();

zend_vm_stack_destroy();

if (fiber->target) {
zend_fiber_context *target = zend_test_fiber_get_context(fiber->target);
zend_fiber_context *target = &fiber->target->context;
zend_fiber_init_context(target, zend_test_fiber_class, zend_test_fiber_execute, EG(fiber_stack_size));
transfer->context = target;

Expand Down Expand Up @@ -157,14 +152,14 @@ static void zend_test_fiber_object_destroy(zend_object *object)
{
zend_test_fiber *fiber = (zend_test_fiber *) object;

if (fiber->status != ZEND_FIBER_STATUS_SUSPENDED) {
if (fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED) {
return;
}

zend_object *exception = EG(exception);
EG(exception) = NULL;

fiber->flags |= ZEND_FIBER_FLAG_DESTROYED;
fiber->context.flags |= ZEND_FIBER_FLAG_DESTROYED;

zend_fiber_transfer transfer = zend_test_fiber_resume(fiber, NULL, false);

Expand All @@ -191,7 +186,7 @@ static void zend_test_fiber_object_free(zend_object *object)
{
zend_test_fiber *fiber = (zend_test_fiber *) object;

if (fiber->status == ZEND_FIBER_STATUS_INIT) {
if (fiber->context.status == ZEND_FIBER_STATUS_INIT) {
// Fiber was never started, so we need to release the reference to the callback.
zval_ptr_dtor(&fiber->fci.function_name);
}
Expand All @@ -213,7 +208,7 @@ static zend_always_inline void delegate_transfer_result(
RETURN_THROWS();
}

if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
if (fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
zval_ptr_dtor(&transfer->value);
RETURN_NULL();
}
Expand Down Expand Up @@ -244,7 +239,7 @@ static ZEND_METHOD(_ZendTestFiber, start)
Z_PARAM_VARIADIC_WITH_NAMED(params, param_count, named_params);
ZEND_PARSE_PARAMETERS_END();

ZEND_ASSERT(fiber->status == ZEND_FIBER_STATUS_INIT);
ZEND_ASSERT(fiber->context.status == ZEND_FIBER_STATUS_INIT);

if (fiber->previous != NULL) {
zend_throw_error(NULL, "Cannot start a fiber that is the target of another fiber");
Expand All @@ -255,11 +250,9 @@ static ZEND_METHOD(_ZendTestFiber, start)
fiber->fci.param_count = param_count;
fiber->fci.named_params = named_params;

zend_fiber_context *context = zend_test_fiber_get_context(fiber);

zend_fiber_init_context(context, zend_test_fiber_class, zend_test_fiber_execute, EG(fiber_stack_size));
zend_fiber_init_context(&fiber->context, zend_test_fiber_class, zend_test_fiber_execute, EG(fiber_stack_size));

fiber->previous = context;
fiber->previous = &fiber->context;

zend_fiber_transfer transfer = zend_test_fiber_resume(fiber, NULL, false);

Expand All @@ -281,7 +274,7 @@ static ZEND_METHOD(_ZendTestFiber, suspend)

zend_fiber_transfer transfer = zend_test_fiber_suspend(fiber, value);

if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
if (fiber->context.flags & ZEND_FIBER_FLAG_DESTROYED) {
// This occurs when the test fiber is GC'ed while suspended.
zval_ptr_dtor(&transfer.value);
zend_throw_graceful_exit();
Expand All @@ -303,7 +296,7 @@ static ZEND_METHOD(_ZendTestFiber, resume)

fiber = (zend_test_fiber *) Z_OBJ_P(getThis());

if (UNEXPECTED(fiber->status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
if (UNEXPECTED(fiber->context.status != ZEND_FIBER_STATUS_SUSPENDED || fiber->caller != NULL)) {
zend_throw_error(NULL, "Cannot resume a fiber that is not suspended");
RETURN_THROWS();
}
Expand All @@ -329,7 +322,7 @@ static ZEND_METHOD(_ZendTestFiber, pipeTo)
target->fci_cache = fci_cache;
Z_TRY_ADDREF(target->fci.function_name);

target->previous = zend_test_fiber_get_context(fiber);
target->previous = &fiber->context;

if (fiber->target) {
OBJ_RELEASE(&fiber->target->std);
Expand Down
2 changes: 1 addition & 1 deletion ext/zend_test/fiber.h
Expand Up @@ -23,7 +23,7 @@ typedef struct _zend_test_fiber zend_test_fiber;

struct _zend_test_fiber {
zend_object std;
ZEND_FIBER_CONTEXT_FIELDS;
zend_fiber_context context;
zend_fiber_context *caller;
zend_fiber_context *previous;
zend_test_fiber *target;
Expand Down

0 comments on commit 859524c

Please sign in to comment.