Skip to content

Add fiber type to better support custom fiber APIs #7105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions Zend/zend_fibers.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static ZEND_NORETURN void zend_fiber_trampoline(transfer_t transfer)
abort();
}

ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_coroutine coroutine, size_t stack_size)
ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size)
{
if (UNEXPECTED(!zend_fiber_stack_allocate(&context->stack, stack_size))) {
return false;
Expand All @@ -211,6 +211,7 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_co
context->handle = make_fcontext(stack, context->stack.size, zend_fiber_trampoline);
ZEND_ASSERT(context->handle != NULL && "make_fcontext() never returns NULL");

context->kind = kind;
context->function = coroutine;

return true;
Expand Down Expand Up @@ -256,7 +257,7 @@ static void zend_fiber_suspend_from(zend_fiber *fiber)
ZEND_ASSERT(fiber->caller && "Fiber has no caller");

zend_fiber_capture_vm_state(&state);
zend_fiber_switch_context(zend_fiber_get_context(fiber->caller));
zend_fiber_switch_context(fiber->caller);
zend_fiber_restore_vm_state(&state);
}

Expand All @@ -267,7 +268,7 @@ static void zend_fiber_switch_to(zend_fiber *fiber)

zend_observer_fiber_switch_notify(EG(current_fiber), context);

fiber->caller = zend_fiber_from_context(EG(current_fiber));
fiber->caller = EG(current_fiber);

zend_fiber_capture_vm_state(&state);
zend_fiber_switch_context(context);
Expand Down Expand Up @@ -352,7 +353,7 @@ static ZEND_STACK_ALIGNED zend_fiber_context *zend_fiber_execute(zend_fiber_cont
fiber->execute_data = NULL;
fiber->stack_bottom = NULL;

return zend_fiber_get_context(fiber->caller);
return fiber->caller;
}

static zend_object *zend_fiber_object_create(zend_class_entry *ce)
Expand Down Expand Up @@ -451,7 +452,7 @@ ZEND_API void zend_fiber_start(zend_fiber *fiber, zval *params, uint32_t param_c
fiber->fci.param_count = param_count;
fiber->fci.named_params = named_params;

if (!zend_fiber_init_context(zend_fiber_get_context(fiber), zend_fiber_execute, EG(fiber_stack_size))) {
if (!zend_fiber_init_context(zend_fiber_get_context(fiber), zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) {
RETURN_THROWS();
}

Expand Down Expand Up @@ -481,7 +482,7 @@ ZEND_METHOD(Fiber, start)

ZEND_API void zend_fiber_suspend(zval *value, zval *return_value)
{
if (UNEXPECTED(EG(current_fiber) == EG(main_fiber))) {
if (UNEXPECTED(EG(current_fiber)->kind != zend_ce_fiber)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend outside of a fiber");
RETURN_THROWS();
}
Expand Down Expand Up @@ -692,7 +693,7 @@ ZEND_METHOD(Fiber, this)
{
ZEND_PARSE_PARAMETERS_NONE();

if (EG(current_fiber) == EG(main_fiber)) {
if (EG(current_fiber)->kind != zend_ce_fiber) {
RETURN_NULL();
}

Expand Down
9 changes: 7 additions & 2 deletions Zend/zend_fibers.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ typedef zend_fiber_context *(*zend_fiber_coroutine)(zend_fiber_context *context)

/* 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; \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use zend_class_entry *, if a CE is used for identification?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is specified as void * to support fibers that are not exposed to PHP userland (pure C fibers) aswell hence restricting it to zend_class_entry * would be difficult due to no class entry being present. In essence this pointer just needs to be a unique address for each type of fiber. I decided to use zend_fiber_ce because it satisfies this requirement and is easy to associate with the fiber.

zend_fiber_coroutine function; \
zend_fiber_stack stack; \
zend_fiber_status status; \
Expand All @@ -98,7 +101,7 @@ struct _zend_fiber {
zend_object std;

/* Fiber that resumed us. */
zend_fiber *caller;
zend_fiber_context *caller;

/* Fiber context fields (embedded to avoid memory allocation). */
ZEND_FIBER_CONTEXT_FIELDS;
Expand Down Expand Up @@ -128,14 +131,16 @@ ZEND_API void zend_fiber_resume(zend_fiber *fiber, zval *value, zval *return_val
ZEND_API void zend_fiber_throw(zend_fiber *fiber, zval *exception, zval *return_value);

/* These functions may be used to create custom fibers (coroutines) using the bundled fiber switching context. */
ZEND_API zend_bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_coroutine coroutine, size_t stack_size);
ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, void *kind, zend_fiber_coroutine coroutine, size_t stack_size);
ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context);
ZEND_API void zend_fiber_switch_context(zend_fiber_context *to);

END_EXTERN_C()

static zend_always_inline zend_fiber *zend_fiber_from_context(zend_fiber_context *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));
}

Expand Down