diff --git a/include/boost/asio/experimental/co_spawn.hpp b/include/boost/asio/experimental/co_spawn.hpp index 8c633234..a587e653 100644 --- a/include/boost/asio/experimental/co_spawn.hpp +++ b/include/boost/asio/experimental/co_spawn.hpp @@ -149,20 +149,20 @@ public: // Support for co_await keyword. bool await_ready() const noexcept { - return false; + return awaitee_->ready(); } // Support for co_await keyword. void await_suspend(detail::coroutine_handle> h) { - awaitee_->start(&h.promise(), h); + awaitee_->attach_caller(&h.promise(), h); } // Support for co_await keyword. template void await_suspend(detail::coroutine_handle> h) { - awaitee_->start(h.promise().top(), h); + awaitee_->attach_caller(h.promise().top(), h); } // Support for co_await keyword. diff --git a/include/boost/asio/experimental/impl/co_spawn.hpp b/include/boost/asio/experimental/impl/co_spawn.hpp index f8285f85..6c9c34e1 100644 --- a/include/boost/asio/experimental/impl/co_spawn.hpp +++ b/include/boost/asio/experimental/impl/co_spawn.hpp @@ -36,36 +36,6 @@ namespace asio { namespace experimental { namespace detail { -// Helper for returning an awaitable "always ready" value. -template -class await_ready_value -{ -public: - template - explicit await_ready_value(Args&&... args) - : value_(std::forward(args)...) - { - } - - bool await_ready() const noexcept - { - return true; - } - - template - void await_suspend(coroutine_handle>) const noexcept - { - } - - T await_resume() - { - return std::move(value_); - } - -private: - T value_; -}; - // Promise object for coroutine at top of thread-of-execution "stack". template class awaiter @@ -132,7 +102,12 @@ public: coroutine_handle::from_promise(*this).destroy(); } - void rethrow_exception() + void unhandled_exception() + { + pending_exception_ = std::current_exception(); + } + + void rethrow_unhandled_exception() { if (pending_exception_) { @@ -141,19 +116,9 @@ public: } } - void unhandled_exception() - { - pending_exception_ = std::current_exception(); - } - - void set_except(std::exception_ptr e) - { - pending_exception_ = e; - } - private: std::size_t ref_count_ = 0; - std::exception_ptr pending_exception_; + std::exception_ptr pending_exception_ = nullptr; alignas(Executor) unsigned char executor_[sizeof(Executor)]; bool has_executor_ = false; }; @@ -183,7 +148,7 @@ public: auto initial_suspend() { - return std::experimental::suspend_always(); + return std::experimental::suspend_never(); } struct final_suspender @@ -212,7 +177,7 @@ public: void set_except(std::exception_ptr e) { - awaiter_->set_except(e); + pending_exception_ = e; } void unhandled_exception() @@ -220,6 +185,15 @@ public: set_except(std::current_exception()); } + void rethrow_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + awaiter* top() { return awaiter_; @@ -230,34 +204,94 @@ public: return caller_; } + bool ready() const + { + return ready_; + } + void wake_caller() { if (caller_) caller_.resume(); + else + ready_ = true; } - await_ready_value await_transform( - this_coro::executor_t) const noexcept + class awaitable_executor { - return await_ready_value(awaiter_->get_executor()); + public: + explicit awaitable_executor(const awaitee_base* a) + : this_(a) + { + } + + bool await_ready() const noexcept + { + return this_->awaiter_ != nullptr; + } + + template + void await_suspend(coroutine_handle>) const noexcept + { + } + + Executor await_resume() + { + return this_->awaiter_->get_executor(); + } + + private: + const awaitee_base* this_; + }; + + awaitable_executor await_transform(this_coro::executor_t) const noexcept + { + return awaitable_executor(this); } - await_ready_value> await_transform( - this_coro::token_t) const noexcept + class awaitable_token { - return await_ready_value>( - await_token(awaiter_)); + public: + explicit awaitable_token(const awaitee_base* a) + : this_(a) + { + } + + bool await_ready() const noexcept + { + return this_->awaiter_ != nullptr; + } + + template + void await_suspend(coroutine_handle>) const noexcept + { + } + + await_token await_resume() + { + return await_token(this_->awaiter_); + } + + private: + const awaitee_base* this_; + }; + + awaitable_token await_transform(this_coro::token_t) const noexcept + { + return awaitable_token(this); } template - T await_transform(T t) const + T await_transform(T&& t) const { - return t; + return std::forward(t); } protected: awaiter* awaiter_ = nullptr; coroutine_handle caller_ = nullptr; + std::exception_ptr pending_exception_ = nullptr; + bool ready_ = false; }; // Promise object for coroutines further down the thread-of-execution "stack". @@ -296,11 +330,11 @@ public: T get() { this->caller_ = nullptr; - this->awaiter_->rethrow_exception(); + this->rethrow_exception(); return std::move(*static_cast(static_cast(result_))); } - void start(awaiter* a, coroutine_handle h) + void attach_caller(awaiter* a, coroutine_handle h) { this->awaiter_ = a; this->caller_ = h; @@ -330,10 +364,10 @@ public: void get() { this->caller_ = nullptr; - this->awaiter_->rethrow_exception(); + this->rethrow_exception(); } - void start(awaiter* a, coroutine_handle h) + void attach_caller(awaiter* a, coroutine_handle h) { this->awaiter_ = a; this->caller_ = h; @@ -434,7 +468,7 @@ public: typename awaiter::ptr ptr(std::move(this->awaiter_)); this->awaitee_->return_void(); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -455,7 +489,7 @@ public: else this->awaitee_->return_void(); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -474,7 +508,7 @@ public: else this->awaitee_->return_void(); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -491,7 +525,7 @@ public: typename awaiter::ptr ptr(std::move(this->awaiter_)); this->awaitee_->return_value(std::forward(arg)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -511,7 +545,7 @@ public: else this->awaitee_->return_value(std::forward(arg)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -531,7 +565,7 @@ public: else this->awaitee_->return_value(std::forward(arg)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -549,7 +583,7 @@ public: this->awaitee_->return_value( std::forward_as_tuple(std::forward(args)...)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -570,7 +604,7 @@ public: this->awaitee_->return_value( std::forward_as_tuple(std::forward(args)...)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } }; @@ -591,7 +625,7 @@ public: this->awaitee_->return_value( std::forward_as_tuple(std::forward(args)...)); this->awaitee_->wake_caller(); - ptr->rethrow_exception(); + ptr->rethrow_unhandled_exception(); } };