-
Notifications
You must be signed in to change notification settings - Fork 19
Receiver lifetime #241
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Receiver lifetime #241
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,6 @@ import std; | |
| #include <concepts> | ||
| #include <coroutine> | ||
| #include <exception> | ||
| #include <thread> | ||
| #include <tuple> | ||
| #include <type_traits> | ||
| #include <utility> | ||
|
|
@@ -49,20 +48,19 @@ import beman.execution.detail.unspecified_promise; | |
| namespace beman::execution::detail { | ||
| template <class Sndr, class Promise> | ||
| class sender_awaitable { | ||
| inline static constexpr bool enable_defence{true}; | ||
| struct unit {}; | ||
| using value_type = | ||
| ::beman::execution::detail::single_sender_value_type<Sndr, ::beman::execution::env_of_t<Promise>>; | ||
| using result_type = ::std::conditional_t<::std::is_void_v<value_type>, unit, value_type>; | ||
| using variant_type = ::std::variant<::std::monostate, result_type, ::std::exception_ptr>; | ||
| using data_type = ::std::tuple<variant_type, ::std::atomic<::std::thread::id>, ::std::coroutine_handle<Promise>>; | ||
| using data_type = ::std::tuple<variant_type, ::std::atomic<bool>, ::std::coroutine_handle<Promise>>; | ||
|
|
||
| struct awaitable_receiver { | ||
| using receiver_concept = ::beman::execution::receiver_t; | ||
|
|
||
| void resume() { | ||
| std::thread::id id(::std::this_thread::get_id()); | ||
| if (not ::std::get<1>(*result_ptr_) | ||
| .compare_exchange_strong(id, ::std::thread::id{}, std::memory_order_acq_rel)) { | ||
| if (not enable_defence || ::std::get<1>(*result_ptr_).exchange(true, std::memory_order_acq_rel)) { | ||
| ::std::get<2>(*result_ptr_).resume(); | ||
| } | ||
| } | ||
|
|
@@ -85,9 +83,7 @@ class sender_awaitable { | |
| } | ||
|
|
||
| void set_stopped() && noexcept { | ||
| std::thread::id id(::std::this_thread::get_id()); | ||
| if (not ::std::get<1>(*result_ptr_) | ||
| .compare_exchange_strong(id, ::std::thread::id{}, ::std::memory_order_acq_rel)) { | ||
| if (not enable_defence || ::std::get<1>(*result_ptr_).exchange(true, ::std::memory_order_acq_rel)) { | ||
| static_cast<::std::coroutine_handle<>>(::std::get<2>(*result_ptr_).promise().unhandled_stopped()) | ||
| .resume(); | ||
| } | ||
|
|
@@ -107,16 +103,14 @@ class sender_awaitable { | |
|
|
||
| public: | ||
| sender_awaitable(Sndr&& sndr, Promise& p) | ||
| : result{::std::monostate{}, ::std::this_thread::get_id(), ::std::coroutine_handle<Promise>::from_promise(p)}, | ||
| : result{::std::monostate{}, false, ::std::coroutine_handle<Promise>::from_promise(p)}, | ||
| state{::beman::execution::connect(::std::forward<Sndr>(sndr), | ||
| sender_awaitable::awaitable_receiver{::std::addressof(result)})} {} | ||
|
|
||
| static constexpr bool await_ready() noexcept { return false; } | ||
| ::std::coroutine_handle<> await_suspend(::std::coroutine_handle<Promise> handle) noexcept { | ||
| ::beman::execution::start(state); | ||
| ::std::thread::id id(::std::this_thread::get_id()); | ||
| if (not ::std::get<1>(this->result) | ||
| .compare_exchange_strong(id, ::std::thread::id{}, ::std::memory_order_acq_rel)) { | ||
| if (enable_defence && ::std::get<1>(this->result).exchange(true, std::memory_order_acq_rel)) { | ||
| if (::std::holds_alternative<::std::monostate>(::std::get<0>(this->result))) { | ||
| return ::std::get<2>(this->result).promise().unhandled_stopped(); | ||
|
Comment on lines
111
to
115
|
||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| //-dk:TODO rRW/// include/beman/execution/detail/store_receiver.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_STORE_RECEIVER | ||
| #define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_STORE_RECEIVER | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <memory> | ||
| #include <utility> | ||
| #include <type_traits> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.connect; | ||
| import beman.execution.detail.connect_result_t; | ||
| import beman.execution.detail.env_of_t; | ||
| import beman.execution.detail.get_completion_signatures; | ||
| import beman.execution.detail.get_env; | ||
| import beman.execution.detail.operation_state; | ||
| import beman.execution.detail.receiver; | ||
| import beman.execution.detail.sender; | ||
| import beman.execution.detail.set_error; | ||
| import beman.execution.detail.set_stopped; | ||
| import beman.execution.detail.set_value; | ||
| import beman.execution.detail.start; | ||
| #else | ||
| #include <beman/execution/detail/connect.hpp> | ||
| #include <beman/execution/detail/connect_result_t.hpp> | ||
| #include <beman/execution/detail/env_of_t.hpp> | ||
| #include <beman/execution/detail/get_completion_signatures.hpp> | ||
| #include <beman/execution/detail/get_env.hpp> | ||
| #include <beman/execution/detail/sender.hpp> | ||
| #include <beman/execution/detail/receiver.hpp> | ||
| #include <beman/execution/detail/set_error.hpp> | ||
| #include <beman/execution/detail/set_stopped.hpp> | ||
| #include <beman/execution/detail/set_value.hpp> | ||
| #include <beman/execution/detail/operation_state.hpp> | ||
| #include <beman/execution/detail/start.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution::detail { | ||
| struct store_receiver_t { | ||
| template <::beman::execution::receiver Rcvr> | ||
| struct receiver { | ||
| using receiver_concept = ::beman::execution::receiver_t; | ||
| Rcvr* rcvr; | ||
| template <typename... Args> | ||
| auto set_value(Args&&... args) && noexcept -> void { | ||
| ::beman::execution::set_value(::std::move(*this->rcvr), ::std::forward<Args>(args)...); | ||
| } | ||
| template <typename Error> | ||
| auto set_error(Error&& error) && noexcept -> void { | ||
| ::beman::execution::set_error(::std::move(*this->rcvr), ::std::forward<Error>(error)); | ||
| } | ||
| auto set_stopped() && noexcept -> void { ::beman::execution::set_stopped(::std::move(*this->rcvr)); } | ||
| auto get_env() const noexcept { return ::beman::execution::get_env(*this->rcvr); } | ||
| }; | ||
| template <::beman::execution::sender Sndr, typename Trans, ::beman::execution::receiver Rcvr> | ||
| struct state { | ||
| using operation_state_concept = ::beman::execution::operation_state_t; | ||
| using env_t = ::beman::execution::env_of_t<Rcvr>; | ||
| using state_t = ::beman::execution::connect_result_t<decltype(::std::declval<Trans>()( | ||
| ::std::declval<Sndr>(), ::std::declval<env_t>())), | ||
| receiver<Rcvr>>; | ||
| Rcvr rcvr; | ||
| state_t op_state; | ||
| template <::beman::execution::sender S, typename T, ::beman::execution::receiver R> | ||
| state(S&& sndr, T&& trans, R&& r) | ||
| : rcvr(::std::forward<R>(r)), | ||
| op_state(::beman::execution::connect( | ||
| ::std::forward<T>(trans)(::std::forward<S>(sndr), ::beman::execution::get_env(this->rcvr)), | ||
| receiver<Rcvr>{::std::addressof(this->rcvr)})) {} | ||
| auto start() & noexcept { ::beman::execution::start(this->op_state); } | ||
| }; | ||
| template <::beman::execution::sender Sndr, typename Trans> | ||
| struct sender { | ||
| using sender_concept = ::beman::execution::sender_t; | ||
| template <typename... Env> | ||
| static consteval auto get_completion_signatures(Env&&... env) noexcept { | ||
| return ::beman::execution:: | ||
| get_completion_signatures<decltype(::std::declval<Trans>()(::std::declval<Sndr>())), Env...>(); | ||
| } | ||
| ::std::remove_cvref_t<Sndr> sndr; | ||
| ::std::remove_cvref_t<Trans> trans; | ||
|
|
||
| template <::beman::execution::receiver Receiver> | ||
| auto connect(Receiver&& r) && { | ||
| static_assert(::beman::execution::operation_state<state<Sndr, Trans, ::std::remove_cvref_t<Receiver>>>); | ||
| return state<Sndr, Trans, ::std::remove_cvref_t<Receiver>>( | ||
| ::std::move(this->sndr), ::std::move(this->trans), ::std::forward<Receiver>(r)); | ||
| } | ||
| template <::beman::execution::receiver Receiver> | ||
| auto connect(Receiver&& r) const& { | ||
| static_assert(::beman::execution::operation_state<state<Sndr, Trans, ::std::remove_cvref_t<Receiver>>>); | ||
| return state<Sndr, Trans, ::std::remove_cvref_t<Receiver>>( | ||
| this->sndr, this->trans, ::std::forward<Receiver>(r)); | ||
| } | ||
| }; | ||
| template <::beman::execution::sender Sndr, typename Trans> | ||
| auto operator()(Sndr&& sndr, Trans&& trans) const { | ||
| static_assert(::beman::execution::sender<sender<Sndr, Trans>>); | ||
| return sender<Sndr, Trans>{::std::forward<Sndr>(sndr), ::std::forward<Trans>(trans)}; | ||
| } | ||
| }; | ||
|
|
||
| inline constexpr store_receiver_t store_receiver{}; | ||
| } // namespace beman::execution::detail | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| // include/beman/execution/detail/unstoppable.hpp -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_UNSTOPPABLE | ||
| #define INCLUDED_INCLUDE_BEMAN_EXECUTION_DETAIL_UNSTOPPABLE | ||
|
|
||
| #include <beman/execution/detail/common.hpp> | ||
| #ifdef BEMAN_HAS_IMPORT_STD | ||
| import std; | ||
| #else | ||
| #include <utility> | ||
| #endif | ||
| #ifdef BEMAN_HAS_MODULES | ||
| import beman.execution.detail.get_stop_token; | ||
| import beman.execution.detail.never_stop_token; | ||
| import beman.execution.detail.prop; | ||
| import beman.execution.detail.sender; | ||
| import beman.execution.detail.write_env; | ||
| #else | ||
| #include <beman/execution/detail/get_stop_token.hpp> | ||
| #include <beman/execution/detail/never_stop_token.hpp> | ||
| #include <beman/execution/detail/prop.hpp> | ||
| #include <beman/execution/detail/sender.hpp> | ||
| #include <beman/execution/detail/write_env.hpp> | ||
| #endif | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| namespace beman::execution::detail { | ||
| struct unstoppable_t { | ||
| template <::beman::execution::sender Sndr> | ||
| auto operator()(Sndr&& sndr) const { | ||
| return ::beman::execution::write_env( | ||
| ::std::forward<Sndr>(sndr), | ||
| ::beman::execution::prop{::beman::execution::get_stop_token, ::beman::execution::never_stop_token{}, {}}); | ||
| } | ||
| }; | ||
| } // namespace beman::execution::detail | ||
|
|
||
| namespace beman::execution { | ||
| using unstoppable_t = ::beman::execution::detail::unstoppable_t; | ||
| inline constexpr ::beman::execution::unstoppable_t unstoppable{}; | ||
| } // namespace beman::execution | ||
|
|
||
| // ---------------------------------------------------------------------------- | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| module; | ||
| // src/beman/execution/store_receiver.cppm -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <beman/execution/detail/store_receiver.hpp> | ||
|
|
||
| export module beman.execution.detail.store_receiver; | ||
|
|
||
| namespace beman::execution::detail { | ||
| export using beman::execution::detail::store_receiver; | ||
| } // namespace beman::execution::detail |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| module; | ||
| // src/beman/execution/unstoppable.cppm -*-C++-*- | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <beman/execution/detail/unstoppable.hpp> | ||
|
|
||
| export module beman.execution.detail.unstoppable; | ||
|
|
||
| namespace beman::execution { | ||
| export using beman::execution::unstoppable; | ||
| } // namespace beman::execution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set(TODO stop_token)is a no-op here (the variable isn’t used) and reads like leftover debugging scaffolding. If the intent is to temporarily disable thestop_tokenexample, it’s clearer to either leave an inline TODO comment where the example would be listed, or gate it behind an option/condition, rather than introducing an unusedTODOvariable.