Skip to content
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
4 changes: 3 additions & 1 deletion Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,9 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
executor_globals->exception_class = NULL;
executor_globals->exception = NULL;
executor_globals->objects_store.object_buckets = NULL;
executor_globals->current_fiber = NULL;
executor_globals->current_fiber_context = NULL;
executor_globals->main_fiber_context = NULL;
executor_globals->active_fiber = NULL;
#ifdef ZEND_WIN32
zend_get_windows_version_info(&executor_globals->windows_version_info);
#endif
Expand Down
135 changes: 69 additions & 66 deletions Zend/zend_fibers.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ static ZEND_NORETURN void zend_fiber_trampoline(boost_context_data data)
/* Initialize transfer struct with a copy of passed data. */
zend_fiber_transfer transfer = *data.transfer;

zend_fiber_context *context = EG(current_fiber);
zend_fiber_context *context = EG(current_fiber_context);

context->function(&transfer);
context->status = ZEND_FIBER_STATUS_DEAD;
Expand Down Expand Up @@ -241,7 +241,7 @@ ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context)

ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
{
zend_fiber_context *from = EG(current_fiber);
zend_fiber_context *from = EG(current_fiber_context);
zend_fiber_context *to = transfer->context;
zend_fiber_vm_state state;

Expand Down Expand Up @@ -272,7 +272,7 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
/* Update transfer context with the current fiber before switching. */
transfer->context = from;

EG(current_fiber) = to;
EG(current_fiber_context) = to;

#ifdef __SANITIZE_ADDRESS__
void *fake_stack = NULL;
Expand All @@ -295,7 +295,7 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)
__sanitizer_finish_switch_fiber(fake_stack, &to->stack.prior_pointer, &to->stack.prior_size);
#endif

EG(current_fiber) = from;
EG(current_fiber_context) = from;

zend_fiber_restore_vm_state(&state);

Expand All @@ -312,11 +312,11 @@ ZEND_API void zend_fiber_switch_context(zend_fiber_transfer *transfer)

static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
{
ZEND_ASSERT(Z_TYPE(transfer->value) == IS_UNDEF && "First context switch into a fiber must not transmit data");

zend_fiber *fiber = zend_fiber_from_context(EG(current_fiber));
zend_fiber *fiber = EG(active_fiber);

/* Determine the current error_reporting ini setting. */
zend_long error_reporting = INI_INT("error_reporting");
/* If error_reporting is 0 and not explicitly set to 0, INI_STR returns a null pointer. */
if (!error_reporting && !INI_STR("error_reporting")) {
error_reporting = E_ALL;
}
Expand Down Expand Up @@ -392,6 +392,50 @@ static zend_always_inline void delegate_transfer_result(
RETURN_COPY_VALUE(&transfer->value);
}

static zend_always_inline zend_fiber_transfer zend_fiber_switch_to(
zend_fiber_context *context, zval *value, bool exception
) {
zend_fiber_transfer transfer = {
.context = context,
.flags = exception ? ZEND_FIBER_TRANSFER_FLAG_ERROR : 0,
};

if (value) {
ZVAL_COPY(&transfer.value, value);
} else {
ZVAL_NULL(&transfer.value);
}

zend_fiber_switch_context(&transfer);

return transfer;
}

static zend_always_inline zend_fiber_transfer zend_fiber_resume(zend_fiber *fiber, zval *value, bool exception)
{
zend_fiber *previous = EG(active_fiber);

fiber->caller = EG(current_fiber_context);
EG(active_fiber) = fiber;

zend_fiber_transfer transfer = zend_fiber_switch_to(fiber->previous, value, exception);

EG(active_fiber) = previous;

return transfer;
}

static zend_always_inline zend_fiber_transfer zend_fiber_suspend(zend_fiber *fiber, zval *value)
{
ZEND_ASSERT(fiber->caller != NULL);

zend_fiber_context *caller = fiber->caller;
fiber->previous = EG(current_fiber_context);
fiber->caller = NULL;

return zend_fiber_switch_to(caller, value, false);
}

static zend_object *zend_fiber_object_create(zend_class_entry *ce)
{
zend_fiber *fiber;
Expand All @@ -416,14 +460,9 @@ static void zend_fiber_object_destroy(zend_object *object)
zend_object *exception = EG(exception);
EG(exception) = NULL;

fiber->caller = EG(current_fiber);
fiber->flags |= ZEND_FIBER_FLAG_DESTROYED;

zend_fiber_transfer transfer = {
.context = zend_fiber_get_context(fiber)
};

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

if (transfer.flags & ZEND_FIBER_TRANSFER_FLAG_ERROR) {
EG(exception) = Z_OBJ(transfer.value);
Expand Down Expand Up @@ -496,13 +535,9 @@ ZEND_METHOD(Fiber, start)
RETURN_THROWS();
}

fiber->caller = EG(current_fiber);

zend_fiber_transfer transfer = {
.context = context
};
fiber->previous = context;

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

delegate_transfer_result(fiber, &transfer, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
Expand All @@ -516,38 +551,24 @@ ZEND_METHOD(Fiber, suspend)
Z_PARAM_ZVAL(value);
ZEND_PARSE_PARAMETERS_END();

if (UNEXPECTED(EG(current_fiber)->kind != zend_ce_fiber)) {
zend_fiber *fiber = EG(active_fiber);

if (UNEXPECTED(!fiber)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend outside of a fiber");
RETURN_THROWS();
}

zend_fiber *fiber = zend_fiber_from_context(EG(current_fiber));
zend_fiber_context *caller = fiber->caller;

if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
RETURN_THROWS();
}

ZEND_ASSERT(fiber->status == ZEND_FIBER_STATUS_RUNNING);
ZEND_ASSERT(caller != NULL);

fiber->caller = NULL;
ZEND_ASSERT(fiber->status == ZEND_FIBER_STATUS_RUNNING || fiber->status == ZEND_FIBER_STATUS_SUSPENDED);

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

zend_fiber_transfer transfer = {
.context = caller
};

if (value) {
ZVAL_COPY(&transfer.value, value);
} else {
ZVAL_NULL(&transfer.value);
}

zend_fiber_switch_context(&transfer);
zend_fiber_transfer transfer = zend_fiber_suspend(fiber, value);

if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
// This occurs when the fiber is GC'ed while suspended.
Expand Down Expand Up @@ -576,21 +597,9 @@ ZEND_METHOD(Fiber, resume)
RETURN_THROWS();
}

fiber->caller = EG(current_fiber);

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

zend_fiber_transfer transfer = {
.context = zend_fiber_get_context(fiber)
};

if (value) {
ZVAL_COPY(&transfer.value, value);
} else {
ZVAL_NULL(&transfer.value);
}

zend_fiber_switch_context(&transfer);
zend_fiber_transfer transfer = zend_fiber_resume(fiber, value, false);

delegate_transfer_result(fiber, &transfer, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
Expand All @@ -611,18 +620,9 @@ ZEND_METHOD(Fiber, throw)
RETURN_THROWS();
}

fiber->caller = EG(current_fiber);

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

zend_fiber_transfer transfer = {
.context = zend_fiber_get_context(fiber),
.flags = ZEND_FIBER_TRANSFER_FLAG_ERROR
};

ZVAL_COPY(&transfer.value, exception);

zend_fiber_switch_context(&transfer);
zend_fiber_transfer transfer = zend_fiber_resume(fiber, exception, true);

delegate_transfer_result(fiber, &transfer, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
Expand Down Expand Up @@ -702,11 +702,13 @@ ZEND_METHOD(Fiber, this)
{
ZEND_PARSE_PARAMETERS_NONE();

if (EG(current_fiber)->kind != zend_ce_fiber) {
zend_fiber *fiber = EG(active_fiber);

if (!fiber) {
RETURN_NULL();
}

RETURN_OBJ_COPY(&zend_fiber_from_context(EG(current_fiber))->std);
RETURN_OBJ_COPY(&fiber->std);
}

ZEND_METHOD(FiberError, __construct)
Expand Down Expand Up @@ -741,11 +743,12 @@ void zend_fiber_init(void)

context->status = ZEND_FIBER_STATUS_RUNNING;

EG(main_fiber) = context;
EG(current_fiber) = context;
EG(main_fiber_context) = context;
EG(current_fiber_context) = context;
EG(active_fiber) = NULL;
}

void zend_fiber_shutdown(void)
{
efree(EG(main_fiber));
efree(EG(main_fiber_context));
}
6 changes: 6 additions & 0 deletions Zend/zend_fibers.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ typedef struct _zend_fiber_vm_state {
int error_reporting;
uint32_t jit_trace_num;
JMP_BUF *bailout;
zend_fiber *active_fiber;
} zend_fiber_vm_state;

struct _zend_fiber {
Expand All @@ -123,6 +124,9 @@ struct _zend_fiber {
/* Fiber that resumed us. */
zend_fiber_context *caller;

/* Fiber that suspended us. */
zend_fiber_context *previous;

/* Callback and info / cache to be used when fiber is started. */
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
Expand Down Expand Up @@ -166,6 +170,7 @@ static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *
state->error_reporting = EG(error_reporting);
state->jit_trace_num = EG(jit_trace_num);
state->bailout = EG(bailout);
state->active_fiber = EG(active_fiber);
}

static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *state)
Expand All @@ -178,6 +183,7 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *
EG(error_reporting) = state->error_reporting;
EG(jit_trace_num) = state->jit_trace_num;
EG(bailout) = state->bailout;
EG(active_fiber) = state->active_fiber;
}

#endif
8 changes: 6 additions & 2 deletions Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ END_EXTERN_C()
typedef struct _zend_vm_stack *zend_vm_stack;
typedef struct _zend_ini_entry zend_ini_entry;
typedef struct _zend_fiber_context zend_fiber_context;
typedef struct _zend_fiber zend_fiber;

struct _zend_compiler_globals {
zend_stack loop_var_stack;
Expand Down Expand Up @@ -249,8 +250,11 @@ struct _zend_executor_globals {

zend_get_gc_buffer get_gc_buffer;

zend_fiber_context *main_fiber;
zend_fiber_context *current_fiber;
zend_fiber_context *main_fiber_context;
zend_fiber_context *current_fiber_context;

/* Active instance of Fiber. */
zend_fiber *active_fiber;

/* Default fiber C stack size. */
zend_long fiber_stack_size;
Expand Down
6 changes: 3 additions & 3 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6895,7 +6895,7 @@ ZEND_METHOD(ReflectionFiber, getTrace)
prev_execute_data = fiber->stack_bottom->prev_execute_data;
fiber->stack_bottom->prev_execute_data = NULL;

if (EG(current_fiber) != zend_fiber_get_context(fiber)) {
if (EG(active_fiber) != fiber) {
// No need to replace current execute data if within the current fiber.
EG(current_execute_data) = fiber->execute_data;
}
Expand All @@ -6915,7 +6915,7 @@ ZEND_METHOD(ReflectionFiber, getExecutingLine)

REFLECTION_CHECK_VALID_FIBER(fiber);

if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
if (EG(active_fiber) == fiber) {
prev_execute_data = execute_data->prev_execute_data;
} else {
prev_execute_data = fiber->execute_data->prev_execute_data;
Expand All @@ -6933,7 +6933,7 @@ ZEND_METHOD(ReflectionFiber, getExecutingFile)

REFLECTION_CHECK_VALID_FIBER(fiber);

if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
if (EG(active_fiber) == fiber) {
prev_execute_data = execute_data->prev_execute_data;
} else {
prev_execute_data = fiber->execute_data->prev_execute_data;
Expand Down