diff --git a/ext-src/php_swoole_coroutine.h b/ext-src/php_swoole_coroutine.h index dc62d3fc353..aebb5c94429 100644 --- a/ext-src/php_swoole_coroutine.h +++ b/ext-src/php_swoole_coroutine.h @@ -80,6 +80,10 @@ struct PHPContext { #ifdef SWOOLE_COROUTINE_MOCK_FIBER_CONTEXT zend_fiber_context *fiber_context; bool fiber_init_notified; +#endif +#ifdef ZEND_CHECK_STACK_LIMIT + void *stack_base; + void *stack_limit; #endif std::stack *defer_tasks; SwapCallback *on_yield; @@ -288,6 +292,10 @@ class PHPCoroutine { static void fiber_context_try_destroy(PHPContext *ctx); static void fiber_context_switch_notify(PHPContext *from, PHPContext *to); static void fiber_context_switch_try_notify(PHPContext *from, PHPContext *to); +#endif +#ifdef ZEND_CHECK_STACK_LIMIT + static void* stack_limit(PHPContext *ctx); + static void* stack_base(PHPContext *ctx); #endif static void interrupt_thread_start(); static void record_last_msec(PHPContext *ctx) { diff --git a/ext-src/swoole_coroutine.cc b/ext-src/swoole_coroutine.cc index c5c9766469b..6a579b3768f 100644 --- a/ext-src/swoole_coroutine.cc +++ b/ext-src/swoole_coroutine.cc @@ -298,6 +298,11 @@ PHPContext *PHPCoroutine::create_context(Args *args) { call->func = func; EG(vm_stack_top) += ZEND_CALL_FRAME_SLOT; +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = stack_base(ctx); + EG(stack_limit) = stack_limit(ctx); +#endif + save_vm_stack(ctx); record_last_msec(ctx); @@ -483,6 +488,10 @@ inline void PHPCoroutine::save_vm_stack(PHPContext *ctx) { ctx->tmp_error_reporting = EG(error_reporting); EG(error_reporting) = ctx->ori_error_reporting; } +#ifdef ZEND_CHECK_STACK_LIMIT + ctx->stack_base = EG(stack_base); + ctx->stack_limit = EG(stack_limit); +#endif } inline void PHPCoroutine::restore_vm_stack(PHPContext *ctx) { @@ -505,6 +514,10 @@ inline void PHPCoroutine::restore_vm_stack(PHPContext *ctx) { if (UNEXPECTED(ctx->in_silence)) { EG(error_reporting) = ctx->tmp_error_reporting; } +#ifdef ZEND_CHECK_STACK_LIMIT + EG(stack_base) = ctx->stack_base; + EG(stack_limit) = ctx->stack_limit; +#endif } inline void PHPCoroutine::save_og(PHPContext *ctx) { @@ -844,6 +857,45 @@ void PHPCoroutine::fiber_context_switch_try_notify(PHPContext *from, PHPContext } #endif /* SWOOLE_COROUTINE_MOCK_FIBER_CONTEXT */ +#ifdef ZEND_CHECK_STACK_LIMIT +void* PHPCoroutine::stack_limit(PHPContext *ctx) +{ +#ifdef SW_USE_THREAD_CONTEXT + return nullptr; +#else + zend_ulong reserve = EG(reserved_stack_size); + +#ifdef __APPLE__ + /* On Apple Clang, the stack probing function ___chkstk_darwin incorrectly + * probes a location that is twice the entered function's stack usage away + * from the stack pointer, when using an alternative stack. + * https://openradar.appspot.com/radar?id=5497722702397440 + */ + reserve = reserve * 2; +#endif + + if (!ctx->co) { + return nullptr; + } + + /* stack->pointer is the end of the stack */ + return (int8_t*)ctx->co->get_ctx().get_stack() + reserve; +#endif +} +void* PHPCoroutine::stack_base(PHPContext *ctx) +{ +#ifdef SW_USE_THREAD_CONTEXT + return nullptr; +#else + if (!ctx->co) { + return nullptr; + } + + return (void*)((uintptr_t)ctx->co->get_ctx().get_stack() + ctx->co->get_ctx().get_stack_size()); +#endif +} +#endif /* ZEND_CHECK_STACK_LIMIT */ + void php_swoole_coroutine_minit(int module_number) { SW_INIT_CLASS_ENTRY_BASE(swoole_coroutine_util, "Swoole\\Coroutine", "Co", swoole_coroutine_methods, nullptr); SW_SET_CLASS_CREATE(swoole_coroutine_util, sw_zend_create_object_deny); diff --git a/include/swoole_coroutine.h b/include/swoole_coroutine.h index d7dbbd6ab16..a773f233010 100644 --- a/include/swoole_coroutine.h +++ b/include/swoole_coroutine.h @@ -131,6 +131,10 @@ class Coroutine { return time(true) - switch_usec + execute_usec; } + coroutine::Context &get_ctx() { + return ctx; + } + static std::unordered_map coroutines; static void set_on_yield(SwapCallback func); diff --git a/include/swoole_coroutine_context.h b/include/swoole_coroutine_context.h index ca3355b192e..de3727444ba 100644 --- a/include/swoole_coroutine_context.h +++ b/include/swoole_coroutine_context.h @@ -57,6 +57,15 @@ class Context { bool swap_out(); #if !defined(SW_USE_THREAD_CONTEXT) && defined(SW_CONTEXT_DETECT_STACK_USAGE) ssize_t get_stack_usage(); +#endif +#ifndef SW_USE_THREAD_CONTEXT + char *get_stack() const { + return stack_; + } + + size_t get_stack_size() const { + return stack_size_; + } #endif bool is_end() const { return end_;