Skip to content

Commit ba91d31

Browse files
committed
Store active Fiber instance separately from current fiber context
This allows another fiber abstraction to create fibers within a Fiber instance (or vice versa), while maintaining the behavior of Fiber::suspend() switching execution to the last call to Fiber::start/resume/throw.
1 parent 681f29e commit ba91d31

File tree

5 files changed

+52
-37
lines changed

5 files changed

+52
-37
lines changed

Zend/zend.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,9 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{
774774
executor_globals->exception_class = NULL;
775775
executor_globals->exception = NULL;
776776
executor_globals->objects_store.object_buckets = NULL;
777-
executor_globals->current_fiber = NULL;
777+
executor_globals->current_fiber_context = NULL;
778+
executor_globals->main_fiber_context = NULL;
779+
executor_globals->active_fiber = NULL;
778780
#ifdef ZEND_WIN32
779781
zend_get_windows_version_info(&executor_globals->windows_version_info);
780782
#endif

Zend/zend_fibers.c

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ static void zend_fiber_stack_free(zend_fiber_stack *stack)
183183

184184
static ZEND_NORETURN void zend_fiber_trampoline(transfer_t transfer)
185185
{
186-
zend_fiber_context *context = EG(current_fiber);
186+
zend_fiber_context *context = EG(current_fiber_context);
187187
zend_fiber_context *from = transfer.data;
188188

189189
from->handle = transfer.context;
@@ -228,7 +228,7 @@ ZEND_API void zend_fiber_destroy_context(zend_fiber_context *context)
228228

229229
ZEND_API zend_fiber_context *zend_fiber_switch_context(zend_fiber_context *to)
230230
{
231-
zend_fiber_context *from = EG(current_fiber);
231+
zend_fiber_context *from = EG(current_fiber_context);
232232
zend_fiber_vm_state state;
233233

234234
ZEND_ASSERT(to && to->handle && "Invalid fiber context");
@@ -245,7 +245,7 @@ ZEND_API zend_fiber_context *zend_fiber_switch_context(zend_fiber_context *to)
245245
from->status = ZEND_FIBER_STATUS_SUSPENDED;
246246
}
247247

248-
EG(current_fiber) = to;
248+
EG(current_fiber_context) = to;
249249

250250
#ifdef __SANITIZE_ADDRESS__
251251
void *fake_stack = NULL;
@@ -261,7 +261,7 @@ ZEND_API zend_fiber_context *zend_fiber_switch_context(zend_fiber_context *to)
261261
__sanitizer_finish_switch_fiber(fake_stack, &to->stack.prior_pointer, &to->stack.prior_size);
262262
#endif
263263

264-
EG(current_fiber) = from;
264+
EG(current_fiber_context) = from;
265265

266266
zend_fiber_context *previous = transfer.data;
267267
previous->handle = transfer.context;
@@ -281,7 +281,6 @@ ZEND_API zend_fiber_context *zend_fiber_switch_context(zend_fiber_context *to)
281281
return previous;
282282
}
283283

284-
285284
static zend_always_inline zend_vm_stack zend_fiber_vm_stack_alloc(size_t size)
286285
{
287286
zend_vm_stack page = emalloc(size);
@@ -352,6 +351,23 @@ static ZEND_STACK_ALIGNED zend_fiber_context *zend_fiber_execute(zend_fiber_cont
352351
return caller;
353352
}
354353

354+
static void zend_fiber_switch_to(zend_fiber *fiber)
355+
{
356+
zend_fiber *previous = EG(active_fiber);
357+
fiber->caller = EG(current_fiber_context);
358+
EG(active_fiber) = fiber;
359+
zend_fiber_switch_context(zend_fiber_get_context(fiber));
360+
EG(active_fiber) = previous;
361+
}
362+
363+
static void zend_fiber_suspend(zend_fiber *fiber)
364+
{
365+
zend_fiber_context *caller = fiber->caller;
366+
ZEND_ASSERT(caller != NULL);
367+
fiber->caller = NULL;
368+
zend_fiber_switch_context(caller);
369+
}
370+
355371
static zend_object *zend_fiber_object_create(zend_class_entry *ce)
356372
{
357373
zend_fiber *fiber;
@@ -376,10 +392,9 @@ static void zend_fiber_object_destroy(zend_object *object)
376392
zend_object *exception = EG(exception);
377393
EG(exception) = NULL;
378394

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

382-
zend_fiber_switch_context(zend_fiber_get_context(fiber));
397+
zend_fiber_switch_to(fiber);
383398

384399
if (EG(exception)) {
385400
if (!exception && EG(current_execute_data) && EG(current_execute_data)->func
@@ -443,15 +458,11 @@ ZEND_METHOD(Fiber, start)
443458
fiber->fci.param_count = param_count;
444459
fiber->fci.named_params = named_params;
445460

446-
zend_fiber_context *context = zend_fiber_get_context(fiber);
447-
448-
if (!zend_fiber_init_context(context, zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) {
461+
if (!zend_fiber_init_context(zend_fiber_get_context(fiber), zend_ce_fiber, zend_fiber_execute, EG(fiber_stack_size))) {
449462
RETURN_THROWS();
450463
}
451464

452-
fiber->caller = EG(current_fiber);
453-
454-
zend_fiber_switch_context(context);
465+
zend_fiber_switch_to(fiber);
455466

456467
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
457468
RETURN_NULL();
@@ -470,33 +481,30 @@ ZEND_METHOD(Fiber, suspend)
470481
Z_PARAM_ZVAL(value);
471482
ZEND_PARSE_PARAMETERS_END();
472483

473-
if (UNEXPECTED(EG(current_fiber)->kind != zend_ce_fiber)) {
484+
zend_fiber *fiber = EG(active_fiber);
485+
486+
if (!fiber) {
474487
zend_throw_error(zend_ce_fiber_error, "Cannot suspend outside of a fiber");
475488
RETURN_THROWS();
476489
}
477490

478-
zend_fiber *fiber = zend_fiber_from_context(EG(current_fiber));
479-
zend_fiber_context *caller = fiber->caller;
480-
481491
if (UNEXPECTED(fiber->flags & ZEND_FIBER_FLAG_DESTROYED)) {
482492
zend_throw_error(zend_ce_fiber_error, "Cannot suspend in a force-closed fiber");
483493
RETURN_THROWS();
484494
}
485495

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

489498
if (value) {
490499
ZVAL_COPY(&fiber->value, value);
491500
} else {
492501
ZVAL_NULL(&fiber->value);
493502
}
494503

495-
fiber->caller = NULL;
496504
fiber->execute_data = EG(current_execute_data);
497505
fiber->stack_bottom->prev_execute_data = NULL;
498506

499-
zend_fiber_switch_context(caller);
507+
zend_fiber_suspend(fiber);
500508

501509
if (fiber->flags & ZEND_FIBER_FLAG_DESTROYED) {
502510
// This occurs when the fiber is GC'ed while suspended.
@@ -539,10 +547,9 @@ ZEND_METHOD(Fiber, resume)
539547
ZVAL_NULL(&fiber->value);
540548
}
541549

542-
fiber->caller = EG(current_fiber);
543550
fiber->stack_bottom->prev_execute_data = EG(current_execute_data);
544551

545-
zend_fiber_switch_context(zend_fiber_get_context(fiber));
552+
zend_fiber_switch_to(fiber);
546553

547554
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
548555
RETURN_NULL();
@@ -571,10 +578,9 @@ ZEND_METHOD(Fiber, throw)
571578
Z_ADDREF_P(exception);
572579
fiber->exception = exception;
573580

574-
fiber->caller = EG(current_fiber);
575581
fiber->stack_bottom->prev_execute_data = EG(current_execute_data);
576582

577-
zend_fiber_switch_context(zend_fiber_get_context(fiber));
583+
zend_fiber_switch_to(fiber);
578584

579585
if (fiber->status == ZEND_FIBER_STATUS_DEAD) {
580586
RETURN_NULL();
@@ -659,11 +665,13 @@ ZEND_METHOD(Fiber, this)
659665
{
660666
ZEND_PARSE_PARAMETERS_NONE();
661667

662-
if (EG(current_fiber)->kind != zend_ce_fiber) {
668+
zend_fiber *fiber = EG(active_fiber);
669+
670+
if (!fiber) {
663671
RETURN_NULL();
664672
}
665673

666-
RETURN_OBJ_COPY(&zend_fiber_from_context(EG(current_fiber))->std);
674+
RETURN_OBJ_COPY(&fiber->std);
667675
}
668676

669677
ZEND_METHOD(FiberError, __construct)
@@ -698,11 +706,12 @@ void zend_fiber_init(void)
698706

699707
context->status = ZEND_FIBER_STATUS_RUNNING;
700708

701-
EG(main_fiber) = context;
702-
EG(current_fiber) = context;
709+
EG(main_fiber_context) = context;
710+
EG(current_fiber_context) = context;
711+
EG(active_fiber) = NULL;
703712
}
704713

705714
void zend_fiber_shutdown(void)
706715
{
707-
efree(EG(main_fiber));
716+
efree(EG(main_fiber_context));
708717
}

Zend/zend_globals.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ END_EXTERN_C()
6262
typedef struct _zend_vm_stack *zend_vm_stack;
6363
typedef struct _zend_ini_entry zend_ini_entry;
6464
typedef struct _zend_fiber_context zend_fiber_context;
65+
typedef struct _zend_fiber zend_fiber;
6566

6667
struct _zend_compiler_globals {
6768
zend_stack loop_var_stack;
@@ -249,8 +250,11 @@ struct _zend_executor_globals {
249250

250251
zend_get_gc_buffer get_gc_buffer;
251252

252-
zend_fiber_context *main_fiber;
253-
zend_fiber_context *current_fiber;
253+
zend_fiber_context *main_fiber_context;
254+
zend_fiber_context *current_fiber_context;
255+
256+
/* Active instance of Fiber. */
257+
zend_fiber *active_fiber;
254258

255259
/* Default fiber C stack size. */
256260
zend_long fiber_stack_size;

ext/reflection/php_reflection.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6895,7 +6895,7 @@ ZEND_METHOD(ReflectionFiber, getTrace)
68956895
prev_execute_data = fiber->stack_bottom->prev_execute_data;
68966896
fiber->stack_bottom->prev_execute_data = NULL;
68976897

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

69166916
REFLECTION_CHECK_VALID_FIBER(fiber);
69176917

6918-
if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
6918+
if (EG(active_fiber) == fiber) {
69196919
prev_execute_data = execute_data->prev_execute_data;
69206920
} else {
69216921
prev_execute_data = fiber->execute_data->prev_execute_data;
@@ -6933,7 +6933,7 @@ ZEND_METHOD(ReflectionFiber, getExecutingFile)
69336933

69346934
REFLECTION_CHECK_VALID_FIBER(fiber);
69356935

6936-
if (EG(current_fiber) == zend_fiber_get_context(fiber)) {
6936+
if (EG(active_fiber) == fiber) {
69376937
prev_execute_data = execute_data->prev_execute_data;
69386938
} else {
69396939
prev_execute_data = fiber->execute_data->prev_execute_data;

ext/zend_test/test.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ static void fiber_enter_observer(zend_fiber_context *from, zend_fiber_context *t
436436
if (ZT_G(observer_fiber_switch)) {
437437
if (to->status == ZEND_FIBER_STATUS_INIT) {
438438
php_printf("<init '%p'>\n", to);
439-
} else if (to != EG(main_fiber)) {
439+
} else if (to->kind == zend_ce_fiber) {
440440
zend_fiber *fiber = zend_fiber_from_context(to);
441441
if (fiber->caller != from) {
442442
return;
@@ -462,7 +462,7 @@ static void fiber_suspend_observer(zend_fiber_context *from, zend_fiber_context
462462
} else {
463463
php_printf("<returned '%p'>\n", from);
464464
}
465-
} else if (from != EG(main_fiber)) {
465+
} else if (from->kind == zend_ce_fiber) {
466466
zend_fiber *fiber = zend_fiber_from_context(from);
467467
if (fiber->caller == NULL) {
468468
php_printf("<suspend '%p'>\n", from);

0 commit comments

Comments
 (0)