@@ -162,10 +162,7 @@ namespace experimental::execution::asio
162162 ::STDEXEC::set_error_t (std::exception_ptr),
163163 ::STDEXEC::set_stopped_t()>;
164164
165- template <typename , typename >
166- class completion_handler ;
167-
168- template <typename Signatures, typename Receiver>
165+ template <typename Mutex, typename Signatures, typename Receiver>
169166 struct operation_state_base
170167 {
171168 class frame_ ;
@@ -180,7 +177,8 @@ namespace experimental::execution::asio
180177
181178 Receiver r_;
182179 asio_impl::cancellation_signal signal_;
183- std::recursive_mutex m_;
180+ STDEXEC_IMMOVABLE_NO_UNIQUE_ADDRESS
181+ Mutex m_;
184182 frame_* frames_{nullptr };
185183 std::exception_ptr ex_;
186184 bool abandoned_{false };
@@ -286,12 +284,13 @@ namespace experimental::execution::asio
286284 callback_;
287285 };
288286
289- template <typename Signatures, typename Receiver>
287+ template <typename Mutex, typename Signatures, typename Receiver>
290288 class completion_handler
291289 {
292- operation_state_base<Signatures, Receiver>* self_;
290+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
291+ operation_state_type_* self_;
293292 public:
294- explicit completion_handler (operation_state_base<Signatures, Receiver> & self) noexcept
293+ explicit completion_handler (operation_state_type_ & self) noexcept
295294 : self_(&self)
296295 {}
297296
@@ -308,7 +307,7 @@ namespace experimental::execution::asio
308307 // When this goes out of scope it might send set stopped or set error, or
309308 // it might defer that to the executor frames above us on the call stack
310309 // (if any)
311- typename operation_state_base<Signatures, Receiver> ::frame_ const frame (*self_);
310+ typename operation_state_type_ ::frame_ const frame (*self_);
312311 self_->abandoned_ = true ;
313312 }
314313 }
@@ -355,17 +354,21 @@ namespace experimental::execution::asio
355354 return self_->signal_ .slot ();
356355 }
357356
358- operation_state_base<Signatures, Receiver> & state () const noexcept
357+ operation_state_type_ & state () const noexcept
359358 {
360359 STDEXEC_ASSERT (self_);
361360 return *self_;
362361 }
363362 };
364363
365- template <typename Signatures, typename Receiver, typename Initiation, typename Args>
366- class operation_state : operation_state_base<Signatures, Receiver>
364+ template <typename Mutex,
365+ typename Signatures,
366+ typename Receiver,
367+ typename Initiation,
368+ typename Args>
369+ class operation_state : operation_state_base<Mutex, Signatures, Receiver>
367370 {
368- using base_ = operation_state_base<Signatures, Receiver>;
371+ using base_ = operation_state_base<Mutex, Signatures, Receiver>;
369372 Initiation init_;
370373 Args args_;
371374 public:
@@ -390,7 +393,7 @@ namespace experimental::execution::asio
390393 [&](auto &&... args)
391394 {
392395 ::STDEXEC::__invoke (static_cast <Initiation&&>(init_),
393- completion_handler<Signatures, Receiver>(*this ),
396+ completion_handler<Mutex, Signatures, Receiver>(*this ),
394397 static_cast<decltype(args)&&>(args)...);
395398 },
396399 std::move (args_));
@@ -415,10 +418,13 @@ namespace experimental::execution::asio
415418 }
416419 };
417420
418- template <typename Signatures, typename Initiation, typename ... Args>
421+ template <typename Mutex, typename Signatures, typename Initiation, typename ... Args>
419422 class sender
420423 {
421424 using args_type_ = std::tuple<std::decay_t <Args>...>;
425+ template <typename Receiver>
426+ using operation_state_type_ =
427+ operation_state<Mutex, Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>;
422428 public:
423429 using sender_concept = ::STDEXEC ::sender_tag;
424430
@@ -445,44 +451,39 @@ namespace experimental::execution::asio
445451 std::remove_cvref_t <Receiver>,
446452 ::STDEXEC ::completion_signatures_of_t <sender const &, ::STDEXEC ::env_of_t <Receiver>>>
447453 constexpr auto connect (Receiver&& receiver) const & noexcept (
448- std::is_nothrow_constructible_v<
449- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
450- Receiver,
451- Initiation const &,
452- args_type_ const &>)
454+ std::is_nothrow_constructible_v<operation_state_type_<Receiver>,
455+ Receiver,
456+ Initiation const &,
457+ args_type_ const &>)
453458 {
454- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
455- static_cast <Receiver&&>(receiver),
456- init_,
457- args_);
459+ return operation_state_type_<Receiver>(static_cast <Receiver&&>(receiver), init_, args_);
458460 }
459461
460462 template <typename Receiver>
461463 requires ::STDEXEC ::receiver_of<
462464 std::remove_cvref_t <Receiver>,
463465 ::STDEXEC ::completion_signatures_of_t <sender, ::STDEXEC ::env_of_t <Receiver>>>
464466 constexpr auto connect (Receiver&& receiver) && noexcept (
465- std::is_nothrow_constructible_v<
466- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
467- Receiver,
468- Initiation,
469- args_type_>)
467+ std::is_nothrow_constructible_v<operation_state_type_<Receiver>,
468+ Receiver,
469+ Initiation,
470+ args_type_>)
470471 {
471- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
472- static_cast <Receiver&&>(receiver),
473- static_cast <Initiation&&>(init_),
474- static_cast <args_type_&&>(args_));
472+ return operation_state_type_<Receiver>(static_cast <Receiver&&>(receiver),
473+ static_cast <Initiation&&>(init_),
474+ static_cast <args_type_&&>(args_));
475475 }
476476 private:
477477 Initiation init_;
478478 args_type_ args_;
479479 };
480480
481- template <typename Signatures, typename Receiver, typename Executor>
481+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
482482 class executor
483483 {
484- operation_state_base<Signatures, Receiver>& self_;
485- Executor ex_;
484+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
485+ operation_state_type_& self_;
486+ Executor ex_;
486487
487488 template <typename F>
488489 constexpr auto wrap_ (F f) const noexcept (std::is_nothrow_move_constructible_v<F>)
@@ -493,8 +494,7 @@ namespace experimental::execution::asio
493494 };
494495 }
495496 public:
496- constexpr explicit executor (operation_state_base<Signatures, Receiver>& self,
497- Executor const & ex) noexcept
497+ constexpr explicit executor (operation_state_type_& self, Executor const & ex) noexcept
498498 : self_(self)
499499 , ex_(ex)
500500 {}
@@ -515,7 +515,7 @@ namespace experimental::execution::asio
515515 constexpr decltype (auto ) prefer(Args&&... args) const noexcept
516516 {
517517 auto const ex = asio_impl::prefer (ex_, static_cast <Args&&>(args)...);
518- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
518+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
519519 }
520520
521521 template <typename ... Args>
@@ -525,7 +525,7 @@ namespace experimental::execution::asio
525525 constexpr decltype (auto ) require(Args&&... args) const noexcept
526526 {
527527 auto const ex = asio_impl::require (ex_, static_cast <Args&&>(args)...);
528- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
528+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
529529 }
530530
531531 template <typename T>
@@ -581,66 +581,86 @@ namespace experimental::execution::asio
581581 bool operator !=(executor const & rhs) const = default ;
582582 };
583583
584+ template <typename Mutex>
585+ struct token
586+ {
587+ static constexpr auto as_default_on = asio::as_default_on<token>;
588+ template <typename IoObject>
589+ using as_default_on_t = asio::as_default_on_t <token, IoObject>;
590+ };
591+
592+ struct null_basic_lockable
593+ {
594+ constexpr void lock () noexcept {}
595+
596+ constexpr void unlock () noexcept {}
597+ };
598+
584599 } // namespace detail::completion_token
585600
586- struct completion_token_t
587- {
588- static constexpr auto as_default_on = asio::as_default_on<completion_token_t >;
589- template <typename IoObject>
590- using as_default_on_t = asio::as_default_on_t <completion_token_t , IoObject>;
591- };
601+ using completion_token_t = detail::completion_token::token<std::recursive_mutex>;
592602
593603 inline completion_token_t const completion_token{};
594604
605+ using thread_unsafe_completion_token_t =
606+ detail::completion_token::token<detail::completion_token::null_basic_lockable>;
607+
608+ inline thread_unsafe_completion_token_t const thread_unsafe_completion_token{};
609+
595610} // namespace experimental::execution::asio
596611
597612namespace exec = experimental::execution;
598613
599614namespace ASIOEXEC_ASIO_NAMESPACE
600615{
601616
602- template <typename ... Signatures>
603- struct async_result <::exec::asio::completion_token_t , Signatures...>
617+ template <typename Mutex, typename ... Signatures>
618+ struct async_result <::exec::asio::detail::completion_token::token<Mutex> , Signatures...>
604619 {
605620 template <typename Initiation, typename ... Args>
606621 requires (std::is_constructible_v<std::decay_t <Args>, Args> && ...)
607- static constexpr auto
608- initiate (Initiation&& i, ::exec::asio::completion_token_t const &, Args&&... args)
622+ static constexpr auto initiate (Initiation&& i,
623+ ::exec::asio::detail::completion_token::token<Mutex> const &,
624+ Args&&... args)
609625 {
610626 return ::exec::asio::detail::completion_token::sender<
627+ Mutex,
611628 ::exec::asio::detail::completion_token::completion_signatures<Signatures...>,
612629 std::remove_cvref_t <Initiation>,
613630 Args...>(static_cast <Initiation&&>(i), static_cast <Args&&>(args)...);
614631 }
615632 };
616633
617- template <typename Signatures, typename Receiver, typename Executor>
634+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
618635 struct associated_executor <
619- ::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver>,
636+ ::exec::asio::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
620637 Executor>
621638 {
622- using type = ::exec::asio::detail::completion_token::executor<Signatures, Receiver, Executor>;
639+ using type =
640+ ::exec::asio::detail::completion_token::executor<Mutex, Signatures, Receiver, Executor>;
623641
624- static type
625- get (::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver> const & h,
626- Executor const & ex) noexcept
642+ static type get (::exec::asio::detail::completion_token::completion_handler<Mutex,
643+ Signatures,
644+ Receiver> const & h,
645+ Executor const & ex) noexcept
627646 {
628647 return type (h.state (), ex);
629648 }
630649 };
631650
632- template <typename Signatures, typename Receiver, typename Allocator>
651+ template <typename Mutex, typename Signatures, typename Receiver, typename Allocator>
633652 requires ::STDEXEC ::__callable<::STDEXEC ::get_allocator_t , ::STDEXEC ::env_of_t <Receiver>>
634653 struct associated_allocator <
635- ::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver>,
654+ ::exec::asio::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
636655 Allocator>
637656 {
638657 using type = std::remove_cvref_t <decltype (::STDEXEC ::get_allocator(
639658 ::STDEXEC::get_env (std::declval<Receiver const &>())))>;
640659
641- static type
642- get (::exec::asio::detail::completion_token::completion_handler<Signatures, Receiver> const & h,
643- ::STDEXEC ::__ignore = {}) noexcept
660+ static type get (::exec::asio::detail::completion_token::completion_handler<Mutex,
661+ Signatures,
662+ Receiver> const & h,
663+ ::STDEXEC ::__ignore = {}) noexcept
644664 {
645665 return ::STDEXEC::get_allocator (::STDEXEC::get_env (h.state ().r_ ));
646666 }
0 commit comments