@@ -154,10 +154,7 @@ namespace experimental::execution::asio
154154 ::STDEXEC::set_error_t (std::exception_ptr),
155155 ::STDEXEC::set_stopped_t()>;
156156
157- template <typename , typename >
158- class completion_handler ;
159-
160- template <typename Signatures, typename Receiver>
157+ template <typename Mutex, typename Signatures, typename Receiver>
161158 struct operation_state_base
162159 {
163160 class frame_ ;
@@ -172,7 +169,8 @@ namespace experimental::execution::asio
172169
173170 Receiver r_;
174171 asio_impl::cancellation_signal signal_;
175- std::recursive_mutex m_;
172+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
173+ Mutex m_;
176174 frame_* frames_{nullptr };
177175 std::exception_ptr ex_;
178176 bool abandoned_{false };
@@ -278,12 +276,13 @@ namespace experimental::execution::asio
278276 callback_;
279277 };
280278
281- template <typename Signatures, typename Receiver>
279+ template <typename Mutex, typename Signatures, typename Receiver>
282280 class completion_handler
283281 {
284- operation_state_base<Signatures, Receiver>* self_;
282+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
283+ operation_state_type_* self_;
285284 public:
286- explicit completion_handler (operation_state_base<Signatures, Receiver> & self) noexcept
285+ explicit completion_handler (operation_state_type_ & self) noexcept
287286 : self_(&self)
288287 {}
289288
@@ -300,7 +299,7 @@ namespace experimental::execution::asio
300299 // When this goes out of scope it might send set stopped or set error, or
301300 // it might defer that to the executor frames above us on the call stack
302301 // (if any)
303- typename operation_state_base<Signatures, Receiver> ::frame_ const frame (*self_);
302+ typename operation_state_type_ ::frame_ const frame (*self_);
304303 self_->abandoned_ = true ;
305304 }
306305 }
@@ -347,17 +346,21 @@ namespace experimental::execution::asio
347346 return self_->signal_ .slot ();
348347 }
349348
350- operation_state_base<Signatures, Receiver> & state () const noexcept
349+ operation_state_type_ & state () const noexcept
351350 {
352351 STDEXEC_ASSERT (self_);
353352 return *self_;
354353 }
355354 };
356355
357- template <typename Signatures, typename Receiver, typename Initiation, typename Args>
358- class operation_state : operation_state_base<Signatures, Receiver>
356+ template <typename Mutex,
357+ typename Signatures,
358+ typename Receiver,
359+ typename Initiation,
360+ typename Args>
361+ class operation_state : operation_state_base<Mutex, Signatures, Receiver>
359362 {
360- using base_ = operation_state_base<Signatures, Receiver>;
363+ using base_ = operation_state_base<Mutex, Signatures, Receiver>;
361364 Initiation init_;
362365 Args args_;
363366 public:
@@ -382,7 +385,7 @@ namespace experimental::execution::asio
382385 [&](auto &&... args)
383386 {
384387 ::STDEXEC::__invoke (static_cast <Initiation&&>(init_),
385- completion_handler<Signatures, Receiver>(*this ),
388+ completion_handler<Mutex, Signatures, Receiver>(*this ),
386389 static_cast<decltype(args)&&>(args)...);
387390 },
388391 std::move (args_));
@@ -407,10 +410,13 @@ namespace experimental::execution::asio
407410 }
408411 };
409412
410- template <typename Signatures, typename Initiation, typename ... Args>
413+ template <typename Mutex, typename Signatures, typename Initiation, typename ... Args>
411414 class sender
412415 {
413416 using args_type_ = std::tuple<std::decay_t <Args>...>;
417+ template <typename Receiver>
418+ using operation_state_type_ =
419+ operation_state<Mutex, Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>;
414420 public:
415421 using sender_concept = ::STDEXEC ::sender_tag;
416422
@@ -437,44 +443,39 @@ namespace experimental::execution::asio
437443 std::remove_cvref_t <Receiver>,
438444 ::STDEXEC ::completion_signatures_of_t <sender const &, ::STDEXEC ::env_of_t <Receiver>>>
439445 constexpr auto connect (Receiver&& receiver) const & noexcept (
440- std::is_nothrow_constructible_v<
441- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
442- Receiver,
443- Initiation const &,
444- args_type_ const &>)
446+ std::is_nothrow_constructible_v<operation_state_type_<Receiver>,
447+ Receiver,
448+ Initiation const &,
449+ args_type_ const &>)
445450 {
446- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
447- static_cast <Receiver&&>(receiver),
448- init_,
449- args_);
451+ return operation_state_type_<Receiver>(static_cast <Receiver&&>(receiver), init_, args_);
450452 }
451453
452454 template <typename Receiver>
453455 requires ::STDEXEC ::receiver_of<
454456 std::remove_cvref_t <Receiver>,
455457 ::STDEXEC ::completion_signatures_of_t <sender, ::STDEXEC ::env_of_t <Receiver>>>
456458 constexpr auto connect (Receiver&& receiver) && noexcept (
457- std::is_nothrow_constructible_v<
458- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
459- Receiver,
460- Initiation,
461- args_type_>)
459+ std::is_nothrow_constructible_v<operation_state_type_<Receiver>,
460+ Receiver,
461+ Initiation,
462+ args_type_>)
462463 {
463- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
464- static_cast <Receiver&&>(receiver),
465- static_cast <Initiation&&>(init_),
466- static_cast <args_type_&&>(args_));
464+ return operation_state_type_<Receiver>(static_cast <Receiver&&>(receiver),
465+ static_cast <Initiation&&>(init_),
466+ static_cast <args_type_&&>(args_));
467467 }
468468 private:
469469 Initiation init_;
470470 args_type_ args_;
471471 };
472472
473- template <typename Signatures, typename Receiver, typename Executor>
473+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
474474 class executor
475475 {
476- operation_state_base<Signatures, Receiver>& self_;
477- Executor ex_;
476+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
477+ operation_state_type_& self_;
478+ Executor ex_;
478479
479480 template <typename F>
480481 constexpr auto wrap_ (F f) const noexcept (std::is_nothrow_move_constructible_v<F>)
@@ -485,8 +486,7 @@ namespace experimental::execution::asio
485486 };
486487 }
487488 public:
488- constexpr explicit executor (operation_state_base<Signatures, Receiver>& self,
489- Executor const & ex) noexcept
489+ constexpr explicit executor (operation_state_type_& self, Executor const & ex) noexcept
490490 : self_(self)
491491 , ex_(ex)
492492 {}
@@ -507,7 +507,7 @@ namespace experimental::execution::asio
507507 constexpr decltype (auto ) prefer(Args&&... args) const noexcept
508508 {
509509 auto const ex = asio_impl::prefer (ex_, static_cast <Args&&>(args)...);
510- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
510+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
511511 }
512512
513513 template <typename ... Args>
@@ -517,7 +517,7 @@ namespace experimental::execution::asio
517517 constexpr decltype (auto ) require(Args&&... args) const noexcept
518518 {
519519 auto const ex = asio_impl::require (ex_, static_cast <Args&&>(args)...);
520- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
520+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
521521 }
522522
523523 template <typename T>
@@ -573,66 +573,86 @@ namespace experimental::execution::asio
573573 bool operator !=(executor const & rhs) const = default ;
574574 };
575575
576+ template <typename Mutex>
577+ struct token
578+ {
579+ static constexpr auto as_default_on = asio::as_default_on<token>;
580+ template <typename IoObject>
581+ using as_default_on_t = asio::as_default_on_t <token, IoObject>;
582+ };
583+
584+ struct null_basic_lockable
585+ {
586+ constexpr void lock () noexcept {}
587+
588+ constexpr void unlock () noexcept {}
589+ };
590+
576591 } // namespace detail::completion_token
577592
578- struct completion_token_t
579- {
580- static constexpr auto as_default_on = asio::as_default_on<completion_token_t >;
581- template <typename IoObject>
582- using as_default_on_t = asio::as_default_on_t <completion_token_t , IoObject>;
583- };
593+ using completion_token_t = detail::completion_token::token<std::recursive_mutex>;
584594
585595 inline completion_token_t const completion_token{};
586596
597+ using thread_unsafe_completion_token_t =
598+ detail::completion_token::token<detail::completion_token::null_basic_lockable>;
599+
600+ inline thread_unsafe_completion_token_t const thread_unsafe_completion_token{};
601+
587602} // namespace experimental::execution::asio
588603
589604namespace exec = experimental::execution;
590605
591606namespace ASIOEXEC_ASIO_NAMESPACE
592607{
593608
594- template <typename ... Signatures>
595- struct async_result <::exec::asio::completion_token_t , Signatures...>
609+ template <typename Mutex, typename ... Signatures>
610+ struct async_result <::exec::asio::detail::completion_token::token<Mutex> , Signatures...>
596611 {
597612 template <typename Initiation, typename ... Args>
598613 requires (std::is_constructible_v<std::decay_t <Args>, Args> && ...)
599- static constexpr auto
600- initiate (Initiation&& i, ::exec::asio::completion_token_t const &, Args&&... args)
614+ static constexpr auto initiate (Initiation&& i,
615+ ::exec::asio::detail::completion_token::token<Mutex> const &,
616+ Args&&... args)
601617 {
602618 return ::exec::asio::detail::completion_token::sender<
619+ Mutex,
603620 ::exec::asio::detail::completion_token::completion_signatures<Signatures...>,
604621 std::remove_cvref_t <Initiation>,
605622 Args...>(static_cast <Initiation&&>(i), static_cast <Args&&>(args)...);
606623 }
607624 };
608625
609- template <typename Signatures, typename Receiver, typename Executor>
626+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
610627 struct associated_executor <
611- ::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver>,
628+ ::exec::asio::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
612629 Executor>
613630 {
614- using type = ::exec::asio::detail::completion_token::executor<Signatures, Receiver, Executor>;
631+ using type =
632+ ::exec::asio::detail::completion_token::executor<Mutex, Signatures, Receiver, Executor>;
615633
616- static type
617- get (::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver> const & h,
618- Executor const & ex) noexcept
634+ static type get (::exec::asio::detail::completion_token::completion_handler<Mutex,
635+ Signatures,
636+ Receiver> const & h,
637+ Executor const & ex) noexcept
619638 {
620639 return type (h.state (), ex);
621640 }
622641 };
623642
624- template <typename Signatures, typename Receiver, typename Allocator>
643+ template <typename Mutex, typename Signatures, typename Receiver, typename Allocator>
625644 requires ::STDEXEC ::__callable<::STDEXEC ::get_allocator_t , ::STDEXEC ::env_of_t <Receiver>>
626645 struct associated_allocator <
627- ::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver>,
646+ ::exec::asio::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
628647 Allocator>
629648 {
630649 using type = std::remove_cvref_t <decltype (::STDEXEC ::get_allocator(
631650 ::STDEXEC::get_env (std::declval<Receiver const &>())))>;
632651
633- static type
634- get (::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver> const & h,
635- ::STDEXEC ::__ignore = {}) noexcept
652+ static type get (::exec::asio::detail::completion_token::completion_handler<Mutex,
653+ Signatures,
654+ Receiver> const & h,
655+ ::STDEXEC ::__ignore = {}) noexcept
636656 {
637657 return ::STDEXEC::get_allocator (::STDEXEC::get_env (h.state ().r_ ));
638658 }
0 commit comments