From e7707dacdf7d3b9e5825a46fe6ff6ec319a446bf Mon Sep 17 00:00:00 2001 From: Hayodea Hekol Date: Sun, 24 May 2026 04:32:44 -0400 Subject: [PATCH] Unify [Non]PostingInvoker into Invoker --- include/spinscale/co/invokerBase.h | 113 ++++------------------- include/spinscale/co/invokers.h | 6 +- include/spinscale/co/nonPostingPromise.h | 2 +- include/spinscale/co/postingPromise.h | 4 +- 4 files changed, 24 insertions(+), 101 deletions(-) diff --git a/include/spinscale/co/invokerBase.h b/include/spinscale/co/invokerBase.h index 3c89be2..81b1dcb 100644 --- a/include/spinscale/co/invokerBase.h +++ b/include/spinscale/co/invokerBase.h @@ -13,25 +13,29 @@ namespace sscl::co { +/** Shared callee-frame owner and awaiter for posting and non-posting promises. + * Posting vs non-posting completion is implemented in each promise's PostBackStatus + * and final_suspend; this type only wires caller handles and reads return values. + */ template -class PostingInvoker +class Invoker { public: - explicit PostingInvoker(PromiseType &_calleePromise) noexcept + explicit Invoker(PromiseType &_calleePromise) noexcept : calleePromise(_calleePromise) {} - PostingInvoker(const PostingInvoker &) = delete; - PostingInvoker &operator=(const PostingInvoker &) = delete; + Invoker(const Invoker &) = delete; + Invoker &operator=(const Invoker &) = delete; - PostingInvoker(PostingInvoker &&other) noexcept + Invoker(Invoker &&other) noexcept : calleePromise(other.calleePromise), ownsFrameDestroy_(std::exchange(other.ownsFrameDestroy_, false)) {} - PostingInvoker &operator=(PostingInvoker &&other) = delete; + Invoker &operator=(Invoker &&other) = delete; - ~PostingInvoker() noexcept + ~Invoker() noexcept { if (!ownsFrameDestroy_) { return; } @@ -47,7 +51,7 @@ public: { static_assert( std::is_base_of_v, - "PostingInvoker caller promise must derive from PromiseChainLink"); + "Invoker caller promise must derive from PromiseChainLink"); calleePromise.callerSchedHandle = callerSchedHandle; calleePromise.setCallerPromiseChainLink(&callerSchedHandle.promise()); @@ -91,11 +95,11 @@ private: /** EXPLANATION: * Every live invoker owns destruction of its callee coroutine frame in - * ~PostingInvoker (via calleePromise.selfSchedHandle). + * ~Invoker (via calleePromise.selfSchedHandle). * * The only time frame destruction is skipped is for a moved-from invoker - * after move construction or move assignment, so we do not double-destroy - * the same handle when get_return_object() returns the invoker by value. + * after move construction, so we do not double-destroy the same handle + * when get_return_object() returns the invoker by value. * * This is not an opt-out for viral vs non-viral callers or for "callee * still running"; callers must keep the invoker alive until the callee @@ -105,91 +109,10 @@ private: }; template -class NonPostingInvoker -{ -public: - explicit NonPostingInvoker(PromiseType &_calleePromise) noexcept - : calleePromise(_calleePromise) - {} +using PostingInvoker = Invoker; - NonPostingInvoker(const NonPostingInvoker &) = delete; - NonPostingInvoker &operator=(const NonPostingInvoker &) = delete; - - NonPostingInvoker(NonPostingInvoker &&other) noexcept - : calleePromise(other.calleePromise), - ownsFrameDestroy_(std::exchange(other.ownsFrameDestroy_, false)) - {} - - NonPostingInvoker &operator=(NonPostingInvoker &&other) = delete; - - ~NonPostingInvoker() noexcept - { - if (!ownsFrameDestroy_) { return; } - - std::coroutine_handle<> handle = calleePromise.selfSchedHandle; - if (handle) { - handle.destroy(); - } - } - - template - bool setCallerSchedHandle( - std::coroutine_handle callerSchedHandle) noexcept - { - static_assert( - std::is_base_of_v, - "NonPostingInvoker caller promise must derive from PromiseChainLink"); - - calleePromise.callerSchedHandle = callerSchedHandle; - calleePromise.setCallerPromiseChainLink( - &callerSchedHandle.promise()); -#ifdef CONFIG_LIBSSCL_DEBUG_CO - std::cout << __func__ << ": " << std::this_thread::get_id() - << " Done setting callerSchedHandle; running CallerFlowExecutor.\n"; -#endif - return calleePromise.postBackStatus.getCallerFlowExecutor()(); - } - - ReturnValues &completedReturnValues() noexcept - { return calleePromise.returnValues; } - - const ReturnValues &completedReturnValues() const noexcept - { return calleePromise.returnValues; } - - auto await_resume() - { - calleePromise.postBackStatus.reset(); - - ReturnValues &returnValues = calleePromise.returnValues; -#ifdef CONFIG_LIBSSCL_DEBUG_CO - std::cout << __func__ << ": " << std::this_thread::get_id() - << " About to check for and rethrow any exception.\n"; -#endif - - if (returnValues.myExceptionPtr) { - std::exception_ptr const captured = returnValues.myExceptionPtr; - std::rethrow_exception(captured); - } - if constexpr (!std::is_void_v) - { - T result = std::move(returnValues.myReturnValue); - return result; - } - } - -protected: - PromiseType &calleePromise; - -private: - /** Every live invoker owns destruction of its callee coroutine frame in - * ~NonPostingInvoker (via calleePromise.selfSchedHandle). - * - * The only time frame destruction is skipped is for a moved-from invoker - * after move construction, so we do not double-destroy the same handle - * when get_return_object() returns the invoker by value. - */ - bool ownsFrameDestroy_ = true; -}; +template +using NonPostingInvoker = Invoker; } // namespace sscl::co diff --git a/include/spinscale/co/invokers.h b/include/spinscale/co/invokers.h index 4bf5e03..5f0b347 100644 --- a/include/spinscale/co/invokers.h +++ b/include/spinscale/co/invokers.h @@ -19,7 +19,7 @@ namespace sscl::co { * PostingPromiseTemplate (no return-value path to a caller). * * The invoker must outlive the callee frame: do not discard the return object - * from get_return_object(). ~PostingInvoker destroys the callee frame. + * from get_return_object(). ~Invoker destroys the callee frame. */ template