Add fiber type to better support custom fiber APIs (#7105)

This commit is contained in:
Martin Schröder 2021-06-07 21:21:05 +02:00 committed by GitHub
parent c220c96c37
commit b76a9dbcf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 15 additions and 9 deletions

View file

@ -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;
@ -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;
@ -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);
}
@ -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);
@ -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)
@ -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();
}
@ -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();
}
@ -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();
}

View file

@ -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; \
zend_fiber_coroutine function; \
zend_fiber_stack stack; \
zend_fiber_status status; \
@ -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;
@ -128,7 +131,7 @@ 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);
@ -136,6 +139,8 @@ 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));
}