#ifndef NON_POSTING_INVOKER_H #define NON_POSTING_INVOKER_H #include #include #include #include #include #include #include namespace sscl::co { template class NonPostingInvoker { public: explicit NonPostingInvoker(PromiseType &_calleePromise) noexcept : calleePromise(_calleePromise) {} 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; }; } // namespace sscl::co #endif // NON_POSTING_INVOKER_H