Skip to content

Commit 51d2dad

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 e085875 commit 51d2dad

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
@@ -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

597612
namespace exec = experimental::execution;
598613

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

Comments
 (0)