Alternative Fiber Internals Refactoring (#7101)

This commit is contained in:
Martin Schröder 2021-06-05 06:25:35 +02:00 committed by GitHub
parent 0dbbf9ec47
commit a65989b127
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 205 additions and 197 deletions

View file

@ -380,6 +380,7 @@ void shutdown_executor(void) /* {{{ */
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown); zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
zend_weakrefs_shutdown(); zend_weakrefs_shutdown();
zend_fiber_shutdown();
zend_try { zend_try {
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator); zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);

View file

@ -78,28 +78,6 @@ extern transfer_t jump_fcontext(fcontext_t to, void *vp);
#define ZEND_FIBER_DEFAULT_PAGE_SIZE 4096 #define ZEND_FIBER_DEFAULT_PAGE_SIZE 4096
#define ZEND_FIBER_BACKUP_EG(stack, stack_page_size, execute_data, error_reporting, trace_num, bailout) do { \
stack = EG(vm_stack); \
stack->top = EG(vm_stack_top); \
stack->end = EG(vm_stack_end); \
stack_page_size = EG(vm_stack_page_size); \
execute_data = EG(current_execute_data); \
error_reporting = EG(error_reporting); \
trace_num = EG(jit_trace_num); \
bailout = EG(bailout); \
} while (0)
#define ZEND_FIBER_RESTORE_EG(stack, stack_page_size, execute_data, error_reporting, trace_num, bailout) do { \
EG(vm_stack) = stack; \
EG(vm_stack_top) = stack->top; \
EG(vm_stack_end) = stack->end; \
EG(vm_stack_page_size) = stack_page_size; \
EG(current_execute_data) = execute_data; \
EG(error_reporting) = error_reporting; \
EG(jit_trace_num) = trace_num; \
EG(bailout) = bailout; \
} while (0)
static size_t zend_fiber_get_page_size(void) static size_t zend_fiber_get_page_size(void)
{ {
static size_t page_size = 0; static size_t page_size = 0;
@ -172,6 +150,11 @@ static bool zend_fiber_stack_allocate(zend_fiber_stack *stack, size_t size)
stack->valgrind = VALGRIND_STACK_REGISTER(base, base + stack->size); stack->valgrind = VALGRIND_STACK_REGISTER(base, base + stack->size);
#endif #endif
#ifdef __SANITIZE_ADDRESS__
stack->prior_pointer = stack->pointer;
stack->prior_size = stack->size;
#endif
return true; return true;
} }
@ -200,24 +183,19 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
static ZEND_NORETURN void zend_fiber_trampoline(transfer_t transfer) static ZEND_NORETURN void zend_fiber_trampoline(transfer_t transfer)
{ {
zend_fiber_context *context = transfer.data; zend_fiber_context *context = EG(current_fiber);
zend_fiber_context *from = transfer.data;
from->handle = transfer.context;
#ifdef __SANITIZE_ADDRESS__ #ifdef __SANITIZE_ADDRESS__
__sanitizer_finish_switch_fiber(NULL, &context->stack.prior_pointer, &context->stack.prior_size); __sanitizer_finish_switch_fiber(NULL, &from->stack.prior_pointer, &from->stack.prior_size);
#endif #endif
context->caller = transfer.context; /* Final context switch, the fiber must not be resumed afterwards! */
zend_fiber_switch_context(context->function(context));
context->function(context);
context->self = NULL;
#ifdef __SANITIZE_ADDRESS__
__sanitizer_start_switch_fiber(NULL, context->stack.prior_pointer, context->stack.prior_size);
#endif
jump_fcontext(context->caller, NULL);
/* Abort here because we are in an inconsistent program state. */
abort(); abort();
} }
@ -230,10 +208,10 @@ ZEND_API bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_co
// Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary. // Stack grows down, calculate the top of the stack. make_fcontext then shifts pointer to lower 16-byte boundary.
void *stack = (void *) ((uintptr_t) context->stack.pointer + context->stack.size); void *stack = (void *) ((uintptr_t) context->stack.pointer + context->stack.size);
context->self = make_fcontext(stack, context->stack.size, zend_fiber_trampoline); context->handle = make_fcontext(stack, context->stack.size, zend_fiber_trampoline);
ZEND_ASSERT(context->self != NULL && "make_fcontext() never returns NULL"); ZEND_ASSERT(context->handle != NULL && "make_fcontext() never returns NULL");
context->function = coroutine; context->function = coroutine;
context->caller = NULL;
return true; return true;
} }
@ -245,81 +223,59 @@ ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context)
ZEND_API void zend_fiber_switch_context(zend_fiber_context *to) ZEND_API void zend_fiber_switch_context(zend_fiber_context *to)
{ {
ZEND_ASSERT(to && to->self && to->stack.pointer && "Invalid fiber context"); zend_fiber_context *from = EG(current_fiber);
ZEND_ASSERT(to && to->handle && "Invalid fiber context");
ZEND_ASSERT(from && "From fiber context must be present");
ZEND_ASSERT(to != from && "Cannot switch into the running fiber context");
#ifdef __SANITIZE_ADDRESS__ #ifdef __SANITIZE_ADDRESS__
void *fake_stack; void *fake_stack = NULL;
__sanitizer_start_switch_fiber(&fake_stack, to->stack.pointer, to->stack.size); __sanitizer_start_switch_fiber(
from->status != ZEND_FIBER_STATUS_DEAD ? &fake_stack : NULL,
to->stack.prior_pointer,
to->stack.prior_size);
#endif #endif
transfer_t transfer = jump_fcontext(to->self, to); EG(current_fiber) = to;
transfer_t transfer = jump_fcontext(to->handle, from);
((zend_fiber_context *) transfer.data)->handle = transfer.context;
EG(current_fiber) = from;
#ifdef __SANITIZE_ADDRESS__ #ifdef __SANITIZE_ADDRESS__
__sanitizer_finish_switch_fiber(fake_stack, &to->stack.prior_pointer, &to->stack.prior_size); __sanitizer_finish_switch_fiber(fake_stack, &to->stack.prior_pointer, &to->stack.prior_size);
#endif #endif
to->self = transfer.context;
}
ZEND_API void zend_fiber_suspend_context(zend_fiber_context *current)
{
ZEND_ASSERT(current && current->caller && current->stack.pointer && "Invalid fiber context");
#ifdef __SANITIZE_ADDRESS__
void *fake_stack;
__sanitizer_start_switch_fiber(&fake_stack, current->stack.prior_pointer, current->stack.prior_size);
#endif
transfer_t transfer = jump_fcontext(current->caller, NULL);
#ifdef __SANITIZE_ADDRESS__
__sanitizer_finish_switch_fiber(fake_stack, &current->stack.prior_pointer, &current->stack.prior_size);
#endif
current->caller = transfer.context;
} }
static void zend_fiber_suspend_from(zend_fiber *fiber) static void zend_fiber_suspend_from(zend_fiber *fiber)
{ {
zend_vm_stack stack; zend_fiber_vm_state state;
size_t stack_page_size;
zend_execute_data *execute_data;
int error_reporting;
uint32_t jit_trace_num;
JMP_BUF *bailout;
ZEND_FIBER_BACKUP_EG(stack, stack_page_size, execute_data, error_reporting, jit_trace_num, bailout); ZEND_ASSERT(fiber->caller && "Fiber has no caller");
zend_fiber_suspend_context(&fiber->context); zend_fiber_capture_vm_state(&state);
zend_fiber_switch_context(zend_fiber_get_context(fiber->caller));
ZEND_FIBER_RESTORE_EG(stack, stack_page_size, execute_data, error_reporting, jit_trace_num, bailout); zend_fiber_restore_vm_state(&state);
} }
static void zend_fiber_switch_to(zend_fiber *fiber) static void zend_fiber_switch_to(zend_fiber *fiber)
{ {
zend_fiber *previous; zend_fiber_context *context = zend_fiber_get_context(fiber);
zend_vm_stack stack; zend_fiber_vm_state state;
size_t stack_page_size;
zend_execute_data *execute_data;
int error_reporting;
uint32_t jit_trace_num;
JMP_BUF *bailout;
previous = EG(current_fiber); zend_observer_fiber_switch_notify(EG(current_fiber), context);
zend_observer_fiber_switch_notify(previous, fiber); fiber->caller = zend_fiber_from_context(EG(current_fiber));
ZEND_FIBER_BACKUP_EG(stack, stack_page_size, execute_data, error_reporting, jit_trace_num, bailout); zend_fiber_capture_vm_state(&state);
zend_fiber_switch_context(context);
zend_fiber_restore_vm_state(&state);
EG(current_fiber) = fiber; fiber->caller = NULL;
zend_fiber_switch_context(&fiber->context); zend_observer_fiber_switch_notify(context, EG(current_fiber));
EG(current_fiber) = previous;
ZEND_FIBER_RESTORE_EG(stack, stack_page_size, execute_data, error_reporting, jit_trace_num, bailout);
zend_observer_fiber_switch_notify(fiber, previous);
if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_BAILOUT)) { if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_BAILOUT)) {
// zend_bailout() was called in the fiber, so call it again in the previous fiber or {main}. // zend_bailout() was called in the fiber, so call it again in the previous fiber or {main}.
@ -339,10 +295,9 @@ static zend_always_inline zend_vm_stack zend_fiber_vm_stack_alloc(size_t size)
return page; return page;
} }
static void ZEND_STACK_ALIGNED zend_fiber_execute(zend_fiber_context *context) static ZEND_STACK_ALIGNED zend_fiber_context *zend_fiber_execute(zend_fiber_context *context)
{ {
zend_fiber *fiber = EG(current_fiber); zend_fiber *fiber = zend_fiber_from_context(context);
ZEND_ASSERT(fiber);
zend_long error_reporting = INI_INT("error_reporting"); zend_long error_reporting = INI_INT("error_reporting");
if (!error_reporting && !INI_STR("error_reporting")) { if (!error_reporting && !INI_STR("error_reporting")) {
@ -396,6 +351,8 @@ static void ZEND_STACK_ALIGNED zend_fiber_execute(zend_fiber_context *context)
zend_vm_stack_destroy(); zend_vm_stack_destroy();
fiber->execute_data = NULL; fiber->execute_data = NULL;
fiber->stack_bottom = NULL; fiber->stack_bottom = NULL;
return zend_fiber_get_context(fiber->caller);
} }
static zend_object *zend_fiber_object_create(zend_class_entry *ce) static zend_object *zend_fiber_object_create(zend_class_entry *ce)
@ -454,7 +411,7 @@ static void zend_fiber_object_free(zend_object *object)
zval_ptr_dtor(&fiber->value); zval_ptr_dtor(&fiber->value);
zend_fiber_destroy_context(&fiber->context); zend_fiber_destroy_context(zend_fiber_get_context(fiber));
zend_object_std_dtor(&fiber->std); zend_object_std_dtor(&fiber->std);
} }
@ -494,7 +451,7 @@ ZEND_API void zend_fiber_start(zend_fiber *fiber, zval *params, uint32_t param_c
fiber->fci.param_count = param_count; fiber->fci.param_count = param_count;
fiber->fci.named_params = named_params; fiber->fci.named_params = named_params;
if (!zend_fiber_init_context(&fiber->context, zend_fiber_execute, EG(fiber_stack_size))) { if (!zend_fiber_init_context(zend_fiber_get_context(fiber), zend_fiber_execute, EG(fiber_stack_size))) {
RETURN_THROWS(); RETURN_THROWS();
} }
@ -524,13 +481,13 @@ ZEND_METHOD(Fiber, start)
ZEND_API void zend_fiber_suspend(zval *value, zval *return_value) ZEND_API void zend_fiber_suspend(zval *value, zval *return_value)
{ {
zend_fiber *fiber = EG(current_fiber); if (UNEXPECTED(EG(current_fiber) == EG(main_fiber))) {
if (UNEXPECTED(!fiber)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend outside of a fiber"); zend_throw_error(zend_ce_fiber_error, "Cannot suspend outside of a fiber");
RETURN_THROWS(); RETURN_THROWS();
} }
zend_fiber *fiber = zend_fiber_from_context(EG(current_fiber));
if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) { if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) {
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber"); zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
RETURN_THROWS(); RETURN_THROWS();
@ -734,17 +691,13 @@ ZEND_METHOD(Fiber, getReturn)
ZEND_METHOD(Fiber, this) ZEND_METHOD(Fiber, this)
{ {
zend_fiber *fiber;
ZEND_PARSE_PARAMETERS_NONE(); ZEND_PARSE_PARAMETERS_NONE();
fiber = EG(current_fiber); if (EG(current_fiber) == EG(main_fiber)) {
if (!fiber) {
RETURN_NULL(); RETURN_NULL();
} }
RETURN_OBJ_COPY(&fiber->std); RETURN_OBJ_COPY(&zend_fiber_from_context(EG(current_fiber))->std);
} }
ZEND_METHOD(FiberError, __construct) ZEND_METHOD(FiberError, __construct)
@ -775,5 +728,15 @@ void zend_register_fiber_ce(void)
void zend_fiber_init(void) void zend_fiber_init(void)
{ {
EG(current_fiber) = NULL; zend_fiber_context *context = ecalloc(1, sizeof(zend_fiber_context));
context->status = ZEND_FIBER_STATUS_RUNNING;
EG(main_fiber) = context;
EG(current_fiber) = context;
}
void zend_fiber_shutdown(void)
{
efree(EG(main_fiber));
} }

View file

@ -23,6 +23,11 @@
#include "zend_API.h" #include "zend_API.h"
#include "zend_types.h" #include "zend_types.h"
#define ZEND_FIBER_GUARD_PAGES 1
#define ZEND_FIBER_DEFAULT_C_STACK_SIZE (4096 * (((sizeof(void *)) < 8) ? 256 : 512))
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))
BEGIN_EXTERN_C() BEGIN_EXTERN_C()
typedef enum { typedef enum {
@ -40,13 +45,11 @@ typedef enum {
void zend_register_fiber_ce(void); void zend_register_fiber_ce(void);
void zend_fiber_init(void); void zend_fiber_init(void);
void zend_fiber_shutdown(void);
extern ZEND_API zend_class_entry *zend_ce_fiber; extern ZEND_API zend_class_entry *zend_ce_fiber;
typedef struct _zend_fiber_context zend_fiber_context; /* Encapsulates the fiber C stack with extension for debugging tools. */
typedef void (*zend_fiber_coroutine)(zend_fiber_context *context);
typedef struct _zend_fiber_stack { typedef struct _zend_fiber_stack {
void *pointer; void *pointer;
size_t size; size_t size;
@ -61,30 +64,49 @@ typedef struct _zend_fiber_stack {
#endif #endif
} zend_fiber_stack; } zend_fiber_stack;
typedef struct _zend_fiber_context { typedef struct _zend_fiber zend_fiber;
void *self; typedef struct _zend_fiber_context zend_fiber_context;
void *caller;
zend_fiber_coroutine function;
zend_fiber_stack stack;
} zend_fiber_context;
typedef struct _zend_fiber { /* Coroutine functions must return a fiber context to switch to after they are finished. */
/* Fiber PHP object handle. */ typedef zend_fiber_context *(*zend_fiber_coroutine)(zend_fiber_context *context);
/* Defined as a macro to allow anonymous embedding. */
#define ZEND_FIBER_CONTEXT_FIELDS \
void *handle; \
zend_fiber_coroutine function; \
zend_fiber_stack stack; \
zend_fiber_status status; \
zend_uchar flags
/* Standalone context (used primarily as pointer type). */
struct _zend_fiber_context {
ZEND_FIBER_CONTEXT_FIELDS;
};
/* Zend VM state that needs to be captured / restored during fiber context switch. */
typedef struct _zend_fiber_vm_state {
zend_vm_stack vm_stack;
size_t vm_stack_page_size;
zend_execute_data *current_execute_data;
int error_reporting;
uint32_t jit_trace_num;
JMP_BUF *bailout;
} zend_fiber_vm_state;
struct _zend_fiber {
/* PHP object handle. */
zend_object std; zend_object std;
/* Status of the fiber, one of the zend_fiber_status values. */ /* Fiber that resumed us. */
zend_fiber_status status; zend_fiber *caller;
/* Flags of the fiber, bit field of the zend_fiber_flag values. */ /* Fiber context fields (embedded to avoid memory allocation). */
zend_uchar flags; ZEND_FIBER_CONTEXT_FIELDS;
/* Callback and info / cache to be used when fiber is started. */ /* Callback and info / cache to be used when fiber is started. */
zend_fcall_info fci; zend_fcall_info fci;
zend_fcall_info_cache fci_cache; zend_fcall_info_cache fci_cache;
/* Context of this fiber, will be initialized during call to Fiber::start(). */
zend_fiber_context context;
/* Current Zend VM execute data being run by the fiber. */ /* Current Zend VM execute data being run by the fiber. */
zend_execute_data *execute_data; zend_execute_data *execute_data;
@ -96,7 +118,7 @@ typedef struct _zend_fiber {
/* Storage for temporaries and fiber return value. */ /* Storage for temporaries and fiber return value. */
zval value; zval value;
} zend_fiber; };
/* These functions create and manipulate a Fiber object, allowing any internal function to start, resume, or suspend a fiber. */ /* These functions create and manipulate a Fiber object, allowing any internal function to start, resume, or suspend a fiber. */
ZEND_API zend_fiber *zend_fiber_create(const zend_fcall_info *fci, const zend_fcall_info_cache *fci_cache); ZEND_API zend_fiber *zend_fiber_create(const zend_fcall_info *fci, const zend_fcall_info_cache *fci_cache);
@ -109,14 +131,41 @@ ZEND_API void zend_fiber_throw(zend_fiber *fiber, zval *exception, zval *return_
ZEND_API zend_bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_coroutine coroutine, size_t stack_size); ZEND_API zend_bool zend_fiber_init_context(zend_fiber_context *context, zend_fiber_coroutine coroutine, size_t stack_size);
ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context); ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context);
ZEND_API void zend_fiber_switch_context(zend_fiber_context *to); ZEND_API void zend_fiber_switch_context(zend_fiber_context *to);
ZEND_API void zend_fiber_suspend_context(zend_fiber_context *current);
#define ZEND_FIBER_GUARD_PAGES 1
#define ZEND_FIBER_DEFAULT_C_STACK_SIZE (4096 * (((sizeof(void *)) < 8) ? 256 : 512))
#define ZEND_FIBER_VM_STACK_SIZE (1024 * sizeof(zval))
END_EXTERN_C() END_EXTERN_C()
static zend_always_inline zend_fiber *zend_fiber_from_context(zend_fiber_context *context)
{
return (zend_fiber *)(((char *) context) - XtOffsetOf(zend_fiber, handle));
}
static zend_always_inline zend_fiber_context *zend_fiber_get_context(zend_fiber *fiber)
{
return (zend_fiber_context *) &fiber->handle;
}
static zend_always_inline void zend_fiber_capture_vm_state(zend_fiber_vm_state *state)
{
state->vm_stack = EG(vm_stack);
state->vm_stack->top = EG(vm_stack_top);
state->vm_stack->end = EG(vm_stack_end);
state->vm_stack_page_size = EG(vm_stack_page_size);
state->current_execute_data = EG(current_execute_data);
state->error_reporting = EG(error_reporting);
state->jit_trace_num = EG(jit_trace_num);
state->bailout = EG(bailout);
}
static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state *state)
{
EG(vm_stack) = state->vm_stack;
EG(vm_stack_top) = state->vm_stack->top;
EG(vm_stack_end) = state->vm_stack->end;
EG(vm_stack_page_size) = state->vm_stack_page_size;
EG(current_execute_data) = state->current_execute_data;
EG(error_reporting) = state->error_reporting;
EG(jit_trace_num) = state->jit_trace_num;
EG(bailout) = state->bailout;
}
#endif #endif

View file

@ -61,8 +61,7 @@ END_EXTERN_C()
typedef struct _zend_vm_stack *zend_vm_stack; typedef struct _zend_vm_stack *zend_vm_stack;
typedef struct _zend_ini_entry zend_ini_entry; typedef struct _zend_ini_entry zend_ini_entry;
typedef struct _zend_fiber zend_fiber; typedef struct _zend_fiber_context zend_fiber_context;
struct _zend_compiler_globals { struct _zend_compiler_globals {
zend_stack loop_var_stack; zend_stack loop_var_stack;
@ -250,8 +249,8 @@ struct _zend_executor_globals {
zend_get_gc_buffer get_gc_buffer; zend_get_gc_buffer get_gc_buffer;
/* Active fiber, NULL when in main thread. */ zend_fiber_context *main_fiber;
zend_fiber *current_fiber; zend_fiber_context *current_fiber;
/* Default fiber C stack size. */ /* Default fiber C stack size. */
zend_long fiber_stack_size; zend_long fiber_stack_size;

View file

@ -264,7 +264,7 @@ ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_han
zend_llist_add_element(&zend_observer_fiber_switch, &handler); zend_llist_add_element(&zend_observer_fiber_switch, &handler);
} }
void zend_observer_fiber_switch_notify(zend_fiber *from, zend_fiber *to) ZEND_API void ZEND_FASTCALL zend_observer_fiber_switch_notify(zend_fiber_context *from, zend_fiber_context *to)
{ {
zend_llist_element *element; zend_llist_element *element;
zend_observer_fiber_switch_handler callback; zend_observer_fiber_switch_handler callback;

View file

@ -78,10 +78,10 @@ typedef void (*zend_observer_error_cb)(int type, zend_string *error_filename, ui
ZEND_API void zend_observer_error_register(zend_observer_error_cb callback); ZEND_API void zend_observer_error_register(zend_observer_error_cb callback);
void zend_observer_error_notify(int type, zend_string *error_filename, uint32_t error_lineno, zend_string *message); void zend_observer_error_notify(int type, zend_string *error_filename, uint32_t error_lineno, zend_string *message);
typedef void (*zend_observer_fiber_switch_handler)(zend_fiber *from, zend_fiber *to); typedef void (*zend_observer_fiber_switch_handler)(zend_fiber_context *from, zend_fiber_context *to);
ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler); ZEND_API void zend_observer_fiber_switch_register(zend_observer_fiber_switch_handler handler);
void zend_observer_fiber_switch_notify(zend_fiber *from, zend_fiber *to); ZEND_API void ZEND_FASTCALL zend_observer_fiber_switch_notify(zend_fiber_context *from, zend_fiber_context *to);
END_EXTERN_C() END_EXTERN_C()

View file

@ -6895,7 +6895,7 @@ ZEND_METHOD(ReflectionFiber, getTrace)
prev_execute_data = fiber->stack_bottom->prev_execute_data; prev_execute_data = fiber->stack_bottom->prev_execute_data;
fiber->stack_bottom->prev_execute_data = NULL; fiber->stack_bottom->prev_execute_data = NULL;
if (EG(current_fiber) != fiber) { if (EG(current_fiber) != zend_fiber_get_context(fiber)) {
// No need to replace current execute data if within the current fiber. // No need to replace current execute data if within the current fiber.
EG(current_execute_data) = fiber->execute_data; EG(current_execute_data) = fiber->execute_data;
} }
@ -6915,7 +6915,7 @@ ZEND_METHOD(ReflectionFiber, getExecutingLine)
REFLECTION_CHECK_VALID_FIBER(fiber); REFLECTION_CHECK_VALID_FIBER(fiber);
if (EG(current_fiber) == fiber) { if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
prev_execute_data = execute_data->prev_execute_data; prev_execute_data = execute_data->prev_execute_data;
} else { } else {
prev_execute_data = fiber->execute_data->prev_execute_data; prev_execute_data = fiber->execute_data->prev_execute_data;
@ -6933,7 +6933,7 @@ ZEND_METHOD(ReflectionFiber, getExecutingFile)
REFLECTION_CHECK_VALID_FIBER(fiber); REFLECTION_CHECK_VALID_FIBER(fiber);
if (EG(current_fiber) == fiber) { if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
prev_execute_data = execute_data->prev_execute_data; prev_execute_data = execute_data->prev_execute_data;
} else { } else {
prev_execute_data = fiber->execute_data->prev_execute_data; prev_execute_data = fiber->execute_data->prev_execute_data;

View file

@ -411,44 +411,40 @@ static void observer_set_user_opcode_handler(const char *opcode_names, user_opco
} }
} }
static void fiber_address_observer(zend_fiber *from, zend_fiber *to) static void fiber_address_observer(zend_fiber_context *from, zend_fiber_context *to)
{ {
if (ZT_G(observer_fiber_switch)) { if (ZT_G(observer_fiber_switch)) {
php_printf("<!-- switching from fiber %p to %p -->\n", from, to); php_printf("<!-- switching from fiber %p to %p -->\n", from, to);
} }
} }
static void fiber_enter_observer(zend_fiber *from, zend_fiber *to) static void fiber_enter_observer(zend_fiber_context *from, zend_fiber_context *to)
{ {
if (ZT_G(observer_fiber_switch)) { if (ZT_G(observer_fiber_switch)) {
if (to) { if (to->status == ZEND_FIBER_STATUS_INIT) {
if (to->status == ZEND_FIBER_STATUS_INIT) { php_printf("<init '%p'>\n", to);
php_printf("<init '%p'>\n", to); } else if (to->status == ZEND_FIBER_STATUS_RUNNING && from->status == ZEND_FIBER_STATUS_RUNNING) {
} else if (to->status == ZEND_FIBER_STATUS_RUNNING && (!from || from->status == ZEND_FIBER_STATUS_RUNNING)) { if (to->flags & ZEND_FIBER_FLAG_DESTROYED) {
if (to->flags & ZEND_FIBER_FLAG_DESTROYED) { php_printf("<destroying '%p'>\n", to);
php_printf("<destroying '%p'>\n", to); } else if (to->status != ZEND_FIBER_STATUS_DEAD) {
} else if (to->status != ZEND_FIBER_STATUS_DEAD) { php_printf("<resume '%p'>\n", to);
php_printf("<resume '%p'>\n", to);
}
} }
} }
} }
} }
static void fiber_suspend_observer(zend_fiber *from, zend_fiber *to) static void fiber_suspend_observer(zend_fiber_context *from, zend_fiber_context *to)
{ {
if (ZT_G(observer_fiber_switch)) { if (ZT_G(observer_fiber_switch)) {
if (from) { if (from->status == ZEND_FIBER_STATUS_SUSPENDED) {
if (from->status == ZEND_FIBER_STATUS_SUSPENDED) { php_printf("<suspend '%p'>\n", from);
php_printf("<suspend '%p'>\n", from); } else if (from->status == ZEND_FIBER_STATUS_DEAD) {
} else if (from->status == ZEND_FIBER_STATUS_DEAD) { if (from->flags & ZEND_FIBER_FLAG_THREW) {
if (from->flags & ZEND_FIBER_FLAG_THREW) { php_printf("<threw '%p'>\n", from);
php_printf("<threw '%p'>\n", from); } else if (from->flags & ZEND_FIBER_FLAG_DESTROYED) {
} else if (from->flags & ZEND_FIBER_FLAG_DESTROYED) { php_printf("<destroyed '%p'>\n", from);
php_printf("<destroyed '%p'>\n", from); } else {
} else { php_printf("<returned '%p'>\n", from);
php_printf("<returned '%p'>\n", from);
}
} }
} }
} }

View file

@ -18,12 +18,12 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_01.php' --> <!-- init '%sobserver_fiber_01.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<returned '%s'> <returned '%s'>

View file

@ -17,12 +17,12 @@ $fiber->start();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_02.php' --> <!-- init '%sobserver_fiber_02.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<destroying '%s'> <destroying '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<destroyed '%s'> <destroyed '%s'>

View file

@ -40,12 +40,12 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_03.php' --> <!-- init '%sobserver_fiber_03.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
int(1) int(1)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
@ -53,9 +53,9 @@ int(1)
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
int(2) int(2)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
@ -63,9 +63,9 @@ int(2)
int(3) int(3)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
int(4) int(4)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
@ -73,5 +73,5 @@ int(4)
int(5) int(5)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<returned '%s'> <returned '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<returned '%s'> <returned '%s'>

View file

@ -27,25 +27,25 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_04.php' --> <!-- init '%sobserver_fiber_04.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<destroying '%s'> <destroying '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<destroyed '%s'> <destroyed '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<returned '%s'> <returned '%s'>

View file

@ -26,25 +26,25 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_05.php' --> <!-- init '%sobserver_fiber_05.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<destroying '%s'> <destroying '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<destroying '%s'> <destroying '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<destroyed '%s'> <destroyed '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<destroyed '%s'> <destroyed '%s'>

View file

@ -23,12 +23,12 @@ try {
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_06.php' --> <!-- init '%sobserver_fiber_06.php' -->
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber 0 to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to 0 --> <!-- switching from fiber %s to %s -->
<threw '%s'> <threw '%s'>