@@ -62,7 +62,7 @@ bool PHPCoroutine::interrupt_thread_running = false;
6262
6363// extern void php_swoole_load_library();
6464
65- #if PHP_VERSION_ID >= 80500
65+ #if PHP_VERSION_ID >= 80400
6666static zif_handler ori_exit_handler = nullptr ;
6767#else
6868static user_opcode_handler_t ori_exit_handler = nullptr ;
@@ -203,12 +203,7 @@ static int coro_exit_handler(zend_execute_data *execute_data) {
203203
204204 if (opline->op1_type != IS_UNUSED) {
205205 if (opline->op1_type == IS_CONST) {
206- // see: https://github.com/php/php-src/commit/e70618aff6f447a298605d07648f2ce9e5a284f5
207- #ifdef EX_CONSTANT
208- exit_status = EX_CONSTANT (opline->op1 );
209- #else
210206 exit_status = RT_CONSTANT (opline, opline->op1 );
211- #endif
212207 } else {
213208 exit_status = EX_VAR (opline->op1 .var );
214209 }
@@ -231,8 +226,8 @@ static int coro_exit_handler(zend_execute_data *execute_data) {
231226 return ZEND_USER_OPCODE_DISPATCH;
232227}
233228#endif
234- #if PHP_VERSION_ID >= 80500
235- /* PHP 8.5 +: exit() is a regular function, intercept via function handler replacement */
229+ #if PHP_VERSION_ID >= 80400
230+ /* PHP 8.4 +: exit() is a regular function, intercept via function handler replacement */
236231PHP_FUNCTION (swoole_exit) {
237232 zend_long flags = 0 ;
238233 if (Coroutine::get_current ()) {
@@ -313,10 +308,9 @@ void PHPCoroutine::activate() {
313308 return ;
314309 }
315310
316- if (zend_hash_str_find_ptr (&module_registry, ZEND_STRL (" xdebug" ))) {
317- php_swoole_fatal_error (
318- E_WARNING,
319- " Using Xdebug in coroutines is extremely dangerous, please notice that it may lead to coredump!" );
311+ /* Apply INI setting for fiber context if not already set via Co::set() */
312+ if (SWOOLE_G (use_fiber_context)) {
313+ Coroutine::set_use_fiber_context (true );
320314 }
321315
322316 /* init reactor and register event wait */
@@ -488,32 +482,40 @@ inline void PHPCoroutine::save_vm_stack(PHPContext *task) {
488482 task->error_handling = EG (error_handling);
489483 task->exception_class = EG (exception_class);
490484 task->exception = EG (exception);
491- if (UNEXPECTED (task->in_silence )) {
492- task->tmp_error_reporting = EG (error_reporting);
493- EG (error_reporting) = task->ori_error_reporting ;
485+ if (!Coroutine::use_fiber_context) {
486+ // With fiber context, zend_fiber_switch_context manages EG(error_reporting).
487+ // Do not modify it here to avoid conflicts.
488+ if (UNEXPECTED (task->in_silence )) {
489+ task->tmp_error_reporting = EG (error_reporting);
490+ EG (error_reporting) = task->ori_error_reporting ;
491+ }
494492 }
495493}
496494
497495inline void PHPCoroutine::restore_vm_stack (PHPContext *task) {
496+ if (!Coroutine::use_fiber_context) {
497+ // With fiber context, zend_fiber_switch_context() saves/restores these fields
498+ // automatically. Restoring them here would conflict and corrupt VM state.
498499#ifdef SW_CORO_SWAP_BAILOUT
499- EG (bailout) = task->bailout ;
500+ EG (bailout) = task->bailout ;
500501#endif
501- EG (vm_stack_top) = task->vm_stack_top ;
502- EG (vm_stack_end) = task->vm_stack_end ;
503- EG (vm_stack) = task->vm_stack ;
504- EG (vm_stack_page_size) = task->vm_stack_page_size ;
505- EG (current_execute_data) = task->execute_data ;
506- EG (jit_trace_num) = task->jit_trace_num ;
502+ EG (vm_stack_top) = task->vm_stack_top ;
503+ EG (vm_stack_end) = task->vm_stack_end ;
504+ EG (vm_stack) = task->vm_stack ;
505+ EG (vm_stack_page_size) = task->vm_stack_page_size ;
506+ EG (current_execute_data) = task->execute_data ;
507+ EG (jit_trace_num) = task->jit_trace_num ;
507508#ifdef ZEND_CHECK_STACK_LIMIT
508- EG (stack_base) = task->stack_base ;
509- EG (stack_limit) = task->stack_limit ;
509+ EG (stack_base) = task->stack_base ;
510+ EG (stack_limit) = task->stack_limit ;
510511#endif
512+ if (UNEXPECTED (task->in_silence )) {
513+ EG (error_reporting) = task->tmp_error_reporting ;
514+ }
515+ }
511516 EG (error_handling) = task->error_handling ;
512517 EG (exception_class) = task->exception_class ;
513518 EG (exception) = task->exception ;
514- if (UNEXPECTED (task->in_silence )) {
515- EG (error_reporting) = task->tmp_error_reporting ;
516- }
517519}
518520
519521inline void PHPCoroutine::save_og (PHPContext *task) {
@@ -608,7 +610,18 @@ void PHPCoroutine::on_close(void *arg) {
608610 if (SwooleG.max_concurrency > 0 && task->pcid == -1 ) {
609611 SwooleWG.worker_concurrency --;
610612 }
611- vm_stack_destroy ();
613+ if (Coroutine::use_fiber_context) {
614+ // With fiber context, EG(vm_stack) is the caller's (restored by zend_fiber_switch_context).
615+ // Destroy the coroutine's VM stack using the pointer saved in the task struct.
616+ zend_vm_stack stack = task->vm_stack ;
617+ while (stack != nullptr ) {
618+ zend_vm_stack p = stack->prev ;
619+ efree (stack);
620+ stack = p;
621+ }
622+ } else {
623+ vm_stack_destroy ();
624+ }
612625 restore_task (origin_task);
613626
614627 swoole_trace_log (SW_TRACE_COROUTINE,
@@ -696,16 +709,20 @@ void PHPCoroutine::main_func(void *arg) {
696709 task->enable_scheduler = true ;
697710
698711#ifdef ZEND_CHECK_STACK_LIMIT
699- if (task->co ) {
700- EG (stack_base) = (void *)((uintptr_t )task->co ->get_context ().get_stack () + task->co ->get_context ().get_stack_size ());
701- zend_ulong reserve = EG (reserved_stack_size);
702- #ifdef __APPLE__
703- reserve = reserve * 2 ;
704- #endif
705- EG (stack_limit) = (int8_t *)task->co ->get_context ().get_stack () + reserve;
706- } else {
707- EG (stack_base) = nullptr ;
708- EG (stack_limit) = nullptr ;
712+ if (!Coroutine::use_fiber_context) {
713+ // Fiber context: zend_fiber_switch_context() sets EG(stack_base/stack_limit) automatically.
714+ // Other backends: we must set them manually from the coroutine stack.
715+ if (task->co ) {
716+ EG (stack_base) = (void *)((uintptr_t )task->co ->get_context ().get_stack () + task->co ->get_context ().get_stack_size ());
717+ zend_ulong reserve = EG (reserved_stack_size);
718+ #ifdef __APPLE__
719+ reserve = reserve * 2 ;
720+ #endif
721+ EG (stack_limit) = (int8_t *)task->co ->get_context ().get_stack () + reserve;
722+ } else {
723+ EG (stack_base) = nullptr ;
724+ EG (stack_limit) = nullptr ;
725+ }
709726 }
710727#endif
711728 save_vm_stack (task);
@@ -788,6 +805,14 @@ void PHPCoroutine::main_func(void *arg) {
788805 }
789806 zval_ptr_dtor (retval);
790807
808+ if (Coroutine::use_fiber_context) {
809+ // Save the coroutine's final VM stack state so on_close can properly
810+ // destroy it. After main_func returns, fiber_func returns to the PHP
811+ // fiber trampoline which does the final context switch. The coroutine's
812+ // EG(vm_stack) is only accessible via this saved pointer in on_close.
813+ save_vm_stack (task);
814+ }
815+
791816 if (UNEXPECTED (EG (exception))) {
792817 zend_exception_error (EG (exception), E_ERROR);
793818 // TODO: php8 don't exit on exceptions, but no reason to continue, fix this in the future
@@ -895,8 +920,8 @@ void php_swoole_coroutine_rinit() {
895920 ori_exit_handler = zend_get_user_opcode_handler (ZEND_EXIT);
896921 zend_set_user_opcode_handler (ZEND_EXIT, coro_exit_handler);
897922#endif
898- #if PHP_VERSION_ID >= 80500
899- /* PHP 8.5 +: exit() is a regular function, replace its handler */
923+ #if PHP_VERSION_ID >= 80400
924+ /* PHP 8.4 +: exit() is a regular function, replace its handler */
900925 zend_function *exit_fn = (zend_function *) zend_hash_str_find_ptr (EG (function_table), ZEND_STRL (" exit" ));
901926 if (exit_fn) {
902927 ori_exit_handler = exit_fn->internal_function .handler ;
@@ -912,7 +937,7 @@ void php_swoole_coroutine_rinit() {
912937}
913938
914939void php_swoole_coroutine_rshutdown () {
915- #if PHP_VERSION_ID >= 80500
940+ #if PHP_VERSION_ID >= 80400
916941 /* Restore original exit() handler */
917942 if (ori_exit_handler) {
918943 zend_function *exit_fn = (zend_function *) zend_hash_str_find_ptr (EG (function_table), ZEND_STRL (" exit" ));
@@ -993,6 +1018,7 @@ static PHP_METHOD(swoole_coroutine, stats) {
9931018 add_assoc_long_ex (return_value, ZEND_STRL (" coroutine_num" ), Coroutine::count ());
9941019 add_assoc_long_ex (return_value, ZEND_STRL (" coroutine_peak_num" ), Coroutine::get_peak_num ());
9951020 add_assoc_long_ex (return_value, ZEND_STRL (" coroutine_last_cid" ), Coroutine::get_last_cid ());
1021+ add_assoc_bool_ex (return_value, ZEND_STRL (" use_fiber_context" ), Coroutine::use_fiber_context);
9961022}
9971023
9981024static PHP_METHOD (swoole_coroutine, run) {
0 commit comments