1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Improve fiber interoperability (#7128)

This commit is contained in:
Aaron Piotrowski
2021-06-10 23:00:07 -05:00
committed by GitHub
parent 16feae57a1
commit e6e6b3e68b
5 changed files with 87 additions and 72 deletions

View File

@@ -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

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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);
@@ -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;
}
@@ -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;
@@ -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);
@@ -496,13 +535,9 @@ ZEND_METHOD(Fiber, start)
RETURN_THROWS();
}
fiber->caller = EG(current_fiber);
fiber->previous = context;
zend_fiber_transfer transfer = {
.context = 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);
}
@@ -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.
@@ -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);
}
@@ -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);
}
@@ -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)
@@ -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));
}

View File

@@ -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 {
@@ -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;
@@ -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)
@@ -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

View File

@@ -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;
@@ -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;

View File

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