@@ -136,10 +136,7 @@ namespace asioexec {
136136 ::STDEXEC::set_stopped_t()
137137 >;
138138
139- template <typename , typename >
140- class completion_handler ;
141-
142- template <typename Signatures, typename Receiver>
139+ template <typename Mutex, typename Signatures, typename Receiver>
143140 struct operation_state_base {
144141 class frame_ ;
145142
@@ -153,7 +150,8 @@ namespace asioexec {
153150
154151 Receiver r_;
155152 asio_impl::cancellation_signal signal_;
156- std::recursive_mutex m_;
153+ [[no_unique_address]]
154+ Mutex m_;
157155 frame_* frames_{nullptr };
158156 std::exception_ptr ex_;
159157 bool abandoned_{false };
@@ -251,11 +249,12 @@ namespace asioexec {
251249 callback_;
252250 };
253251
254- template <typename Signatures, typename Receiver>
252+ template <typename Mutex, typename Signatures, typename Receiver>
255253 class completion_handler {
256- operation_state_base<Signatures, Receiver>* self_;
254+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
255+ operation_state_type_* self_;
257256 public:
258- explicit completion_handler (operation_state_base<Signatures, Receiver> & self) noexcept
257+ explicit completion_handler (operation_state_type_ & self) noexcept
259258 : self_(&self) {
260259 }
261260
@@ -270,7 +269,7 @@ namespace asioexec {
270269 // When this goes out of scope it might send set stopped or set error, or
271270 // it might defer that to the executor frames above us on the call stack
272271 // (if any)
273- const typename operation_state_base<Signatures, Receiver> ::frame_ frame (*self_);
272+ const typename operation_state_type_ ::frame_ frame (*self_);
274273 self_->abandoned_ = true ;
275274 }
276275 }
@@ -309,15 +308,20 @@ namespace asioexec {
309308 return self_->signal_ .slot ();
310309 }
311310
312- operation_state_base<Signatures, Receiver> & state () const noexcept {
311+ operation_state_type_ & state () const noexcept {
313312 STDEXEC_ASSERT (self_);
314313 return *self_;
315314 }
316315 };
317316
318- template <typename Signatures, typename Receiver, typename Initiation, typename Args>
319- class operation_state : operation_state_base<Signatures, Receiver> {
320- using base_ = operation_state_base<Signatures, Receiver>;
317+ template <
318+ typename Mutex,
319+ typename Signatures,
320+ typename Receiver,
321+ typename Initiation,
322+ typename Args>
323+ class operation_state : operation_state_base<Mutex, Signatures, Receiver> {
324+ using base_ = operation_state_base<Mutex, Signatures, Receiver>;
321325 Initiation init_;
322326 Args args_;
323327 public:
@@ -339,7 +343,7 @@ namespace asioexec {
339343 [&](auto &&... args) {
340344 std::invoke (
341345 static_cast <Initiation&&>(init_),
342- completion_handler<Signatures, Receiver>(*this ),
346+ completion_handler<Mutex, Signatures, Receiver>(*this ),
343347 static_cast <decltype (args)&&>(args)...);
344348 },
345349 std::move (args_));
@@ -362,9 +366,12 @@ namespace asioexec {
362366 }
363367 };
364368
365- template <typename Signatures, typename Initiation, typename ... Args>
369+ template <typename Mutex, typename Signatures, typename Initiation, typename ... Args>
366370 class sender {
367371 using args_type_ = std::tuple<std::decay_t <Args>...>;
372+ template <typename Receiver>
373+ using operation_state_type_ =
374+ operation_state<Mutex, Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>;
368375 public:
369376 using sender_concept = ::STDEXEC ::sender_t ;
370377
@@ -388,32 +395,25 @@ namespace asioexec {
388395 template <typename Receiver>
389396 requires ::STDEXEC ::receiver_of<
390397 std::remove_cvref_t <Receiver>,
391- ::STDEXEC ::completion_signatures_of_t <const sender&, ::STDEXEC ::env_of_t <Receiver>>
392- >
393- constexpr auto connect (Receiver&& receiver) const & noexcept (
394- std::is_nothrow_constructible_v<
395- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
396- Receiver,
397- const Initiation&,
398- const args_type_&
399- >) {
400- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
401- static_cast <Receiver&&>(receiver), init_, args_);
398+ ::STDEXEC ::completion_signatures_of_t <const sender&, ::STDEXEC ::env_of_t <Receiver>>>
399+ constexpr auto connect (Receiver&& receiver) const & noexcept (std::is_nothrow_constructible_v<
400+ operation_state_type_<Receiver>,
401+ Receiver,
402+ const Initiation&,
403+ const args_type_&>) {
404+ return operation_state_type_<Receiver>(static_cast <Receiver&&>(receiver), init_, args_);
402405 }
403406
404407 template <typename Receiver>
405408 requires ::STDEXEC ::receiver_of<
406409 std::remove_cvref_t <Receiver>,
407- ::STDEXEC ::completion_signatures_of_t <sender, ::STDEXEC ::env_of_t <Receiver>>
408- >
409- constexpr auto connect (Receiver&& receiver) && noexcept (
410- std::is_nothrow_constructible_v<
411- operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>,
412- Receiver,
413- Initiation,
414- args_type_
415- >) {
416- return operation_state<Signatures, std::remove_cvref_t <Receiver>, Initiation, args_type_>(
410+ ::STDEXEC ::completion_signatures_of_t <sender, ::STDEXEC ::env_of_t <Receiver>>>
411+ constexpr auto connect (Receiver&& receiver) && noexcept (std::is_nothrow_constructible_v<
412+ operation_state_type_<Receiver>,
413+ Receiver,
414+ Initiation,
415+ args_type_>) {
416+ return operation_state_type_<Receiver>(
417417 static_cast <Receiver&&>(receiver),
418418 static_cast <Initiation&&>(init_),
419419 static_cast <args_type_&&>(args_));
@@ -423,9 +423,10 @@ namespace asioexec {
423423 args_type_ args_;
424424 };
425425
426- template <typename Signatures, typename Receiver, typename Executor>
426+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
427427 class executor {
428- operation_state_base<Signatures, Receiver>& self_;
428+ using operation_state_type_ = operation_state_base<Mutex, Signatures, Receiver>;
429+ operation_state_type_& self_;
429430 Executor ex_;
430431
431432 template <typename F>
@@ -435,9 +436,7 @@ namespace asioexec {
435436 };
436437 }
437438 public:
438- constexpr explicit executor (
439- operation_state_base<Signatures, Receiver>& self,
440- const Executor& ex) noexcept
439+ constexpr explicit executor (operation_state_type_& self, const Executor& ex) noexcept
441440 : self_(self)
442441 , ex_(ex) {
443442 }
@@ -456,7 +455,7 @@ namespace asioexec {
456455 }
457456 constexpr decltype (auto ) prefer(Args&&... args) const noexcept {
458457 const auto ex = asio_impl::prefer (ex_, static_cast <Args&&>(args)...);
459- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
458+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
460459 }
461460
462461 template <typename ... Args>
@@ -465,7 +464,7 @@ namespace asioexec {
465464 }
466465 constexpr decltype (auto ) require(Args&&... args) const noexcept {
467466 const auto ex = asio_impl::require (ex_, static_cast <Args&&>(args)...);
468- return executor<Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
467+ return executor<Mutex, Signatures, Receiver, std::remove_cvref_t <decltype (ex)>>(self_, ex);
469468 }
470469
471470 template <typename T>
@@ -516,59 +515,78 @@ namespace asioexec {
516515 bool operator !=(const executor& rhs) const = default ;
517516 };
518517
518+ template <typename Mutex>
519+ struct t {
520+ static constexpr auto as_default_on = ::asioexec::as_default_on<t>;
521+ template <typename IoObject>
522+ using as_default_on_t = ::asioexec::as_default_on_t <t, IoObject>;
523+ };
524+
525+ struct null_basic_lockable {
526+ constexpr void lock () noexcept {
527+ }
528+ constexpr void unlock () noexcept {
529+ }
530+ };
531+
519532 } // namespace detail::completion_token
520533
521- struct completion_token_t {
522- static constexpr auto as_default_on = asioexec::as_default_on<completion_token_t >;
523- template <typename IoObject>
524- using as_default_on_t = asioexec::as_default_on_t <completion_token_t , IoObject>;
525- };
534+ using completion_token_t = detail::completion_token::t<std::recursive_mutex>;
526535
527536 inline const completion_token_t completion_token{};
528537
538+ using thread_unsafe_completion_token_t =
539+ detail::completion_token::t<detail::completion_token::null_basic_lockable>;
540+
541+ inline const thread_unsafe_completion_token_t thread_unsafe_completion_token{};
542+
529543} // namespace asioexec
530544
531545namespace ASIOEXEC_ASIO_NAMESPACE {
532546
533- template <typename ... Signatures>
534- struct async_result <::asioexec::completion_token_t , Signatures...> {
547+ template <typename Mutex, typename ... Signatures>
548+ struct async_result <::asioexec::detail::completion_token::t<Mutex> , Signatures...> {
535549 template <typename Initiation, typename ... Args>
536550 requires (std::is_constructible_v<std::decay_t <Args>, Args> && ...)
537- static constexpr auto
538- initiate (Initiation&& i, const ::asioexec::completion_token_t &, Args&&... args) {
551+ static constexpr auto initiate (
552+ Initiation&& i,
553+ const ::asioexec::detail::completion_token::t<Mutex>&,
554+ Args&&... args) {
539555 return ::asioexec::detail::completion_token::sender<
556+ Mutex,
540557 ::asioexec::detail::completion_token::completion_signatures<Signatures...>,
541558 std::remove_cvref_t <Initiation>,
542- Args...
543- >(static_cast <Initiation&&>(i), static_cast <Args&&>(args)...);
559+ Args...>(static_cast <Initiation&&>(i), static_cast <Args&&>(args)...);
544560 }
545561 };
546562
547- template <typename Signatures, typename Receiver, typename Executor>
563+ template <typename Mutex, typename Signatures, typename Receiver, typename Executor>
548564 struct associated_executor <
549- ::asioexec::detail::completion_token::completion_handler<Signatures, Receiver>,
550- Executor
551- > {
552- using type = ::asioexec::detail::completion_token::executor<Signatures, Receiver, Executor>;
565+ ::asioexec::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
566+ Executor> {
567+ using type =
568+ ::asioexec::detail::completion_token::executor<Mutex, Signatures, Receiver, Executor>;
553569
554570 static type get (
555- const ::asioexec::detail::completion_token::completion_handler<Signatures, Receiver>& h,
571+ const ::asioexec::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>&
572+ h,
556573 const Executor& ex) noexcept {
557574 return type (h.state (), ex);
558575 }
559576 };
560577
561- template <typename Signatures, typename Receiver, typename Allocator>
578+ template <typename Mutex, typename Signatures, typename Receiver, typename Allocator>
562579 requires requires (const Receiver& r) { ::STDEXEC::get_allocator (::STDEXEC::get_env (r)); }
563580 struct associated_allocator <
564- ::asioexec::detail::completion_token::completion_handler<Signatures, Receiver>,
581+ ::asioexec::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>,
565582 Allocator
566583 > {
567584 using type = std::remove_cvref_t <decltype (::STDEXEC ::get_allocator(
568585 ::STDEXEC::get_env (std::declval<const Receiver&>())))>;
569586
570587 static type get (
571- const ::asioexec::detail::completion_token::completion_handler<Signatures, Receiver>& h,
588+ const ::asioexec::detail::completion_token::completion_handler<Mutex, Signatures, Receiver>&
589+ h,
572590 const Allocator&) noexcept {
573591 return ::STDEXEC::get_allocator (::STDEXEC::get_env (h.state ().r_ ));
574592 }
0 commit comments