Skip to content

Commit 6ffbd0a

Browse files
committed
exec::asio::thread_unsafe_completion_token & _use_sender
For general purpose (i.e. potentially multithreaded) use the asynchronous operations which result when passing the exec::asio:: completion_token and ::use_sender completion tokens must use a recursive mutex internally. However if the user knows that no multithreaded use will occur this recursive mutex is pure overhead. Provided the exec::asio::thread_unsafe_completion_token and _use_sender completion tokens which do not make use of a recursive mutex for the aforementioned use case.
1 parent d9d52c2 commit 6ffbd0a

6 files changed

Lines changed: 129 additions & 74 deletions

File tree

include/asioexec/completion_token.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,24 @@ namespace asioexec
3636
"exec::asio::completion_token_t "
3737
"instead.")]] = exec::asio::completion_token_t;
3838

39+
using thread_unsafe_completion_token_t
40+
[[deprecated("asioexec::thread_unsafe_completion_token_t "
41+
"is deprecated. Please use "
42+
"exec::asio::thread_unsafe_completion_token_"
43+
"t instead.")]] = exec::asio::thread_unsafe_completion_token_t;
44+
3945
inline constexpr auto const & completion_token [[deprecated("asioexec::completion_token is "
4046
"deprecated. Please use "
4147
"exec::asio::completion_token "
4248
"instead.")]]
4349
= exec::asio::completion_token;
50+
51+
inline constexpr auto const & thread_unsafe_completion_token [[deprecated("asioexec::thread_"
52+
"unsafe_completion_"
53+
"token is deprecated. "
54+
"Please use "
55+
"exec::asio::thread_"
56+
"unsafe_completion_"
57+
"token instead.")]]
58+
= exec::asio::thread_unsafe_completion_token;
4459
} // namespace asioexec

include/asioexec/use_sender.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,19 @@ namespace asioexec
3636
"exec::asio::use_sender_t "
3737
"instead.")]] = exec::asio::use_sender_t;
3838

39+
using thread_unsafe_use_sender_t [[deprecated(
40+
"asioexec::thread_unsafe_use_sender_t is deprecated. Please use "
41+
"exec::asio::thread_unsafe_use_sender_t instead.")]] = exec::asio::thread_unsafe_use_sender_t;
42+
3943
inline constexpr auto const & use_sender [[deprecated("asioexec::use_sender is deprecated. "
4044
"Please use exec::asio::use_sender "
4145
"instead.")]]
4246
= exec::asio::use_sender;
47+
48+
inline constexpr auto const & thread_unsafe_use_sender [[deprecated("asioexec::thread_unsafe_use_"
49+
"sender is deprecated. "
50+
"Please use "
51+
"exec::asio::thread_unsafe_"
52+
"use_sender instead.")]]
53+
= exec::asio::thread_unsafe_use_sender;
4354
} // namespace asioexec

include/exec/asio/completion_token.hpp

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -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

589604
namespace exec = experimental::execution;
590605

591606
namespace 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

Comments
 (0)