26template <OpFinishHandleLike Handle>
class HandleBox {
28 HandleBox(Handle h) : handle_(std::move(h)) {}
30 Handle &get() {
return handle_; }
36template <
typename Func, OpFinishHandleLike HandleBase>
37class HandleBox<ZeroCopyMixin<Func, HandleBase>> {
39 using Handle = ZeroCopyMixin<Func, HandleBase>;
40 HandleBox(Handle h) : handle_ptr_(new Handle(std::move(h))) {}
42 Handle &get() {
return *handle_ptr_; }
48template <OpFinishHandleLike Handle, PrepFuncLike Func>
class OpAwaiterBase {
50 using HandleType = Handle;
52 OpAwaiterBase(HandleBox<Handle> handle, Func func)
53 : prep_func_(func), finish_handle_(std::move(handle)) {}
54 OpAwaiterBase(OpAwaiterBase &&) =
default;
56 OpAwaiterBase(
const OpAwaiterBase &) =
delete;
57 OpAwaiterBase &operator=(
const OpAwaiterBase &) =
delete;
58 OpAwaiterBase &operator=(OpAwaiterBase &&) =
delete;
61 HandleType *get_handle() {
return &finish_handle_.get(); }
63 void init_finish_handle() { }
65 void register_operation(
unsigned int flags) {
66 auto &context = detail::Context::current();
67 auto *ring = context.ring();
69 context.runtime()->pend_work();
71 io_uring_sqe *sqe = prep_func_(ring);
72 assert(sqe &&
"prep_func must return a valid sqe");
73 sqe->flags |=
static_cast<uint8_t
>(flags);
74 io_uring_sqe_set_data(
75 sqe, encode_work(&finish_handle_.get(), WorkType::Common));
79 bool await_ready() {
return false; }
81 template <
typename PromiseType>
82 void await_suspend(std::coroutine_handle<PromiseType> h) {
84 finish_handle_.get().set_invoker(&h.promise());
85 register_operation(0);
88 auto await_resume() {
return finish_handle_.get().extract_result(); }
92 HandleBox<Handle> finish_handle_;
95template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler>
96class [[nodiscard]] OpAwaiter
97 :
public OpAwaiterBase<OpFinishHandle<CQEHandler>, PrepFunc> {
99 using Base = OpAwaiterBase<OpFinishHandle<CQEHandler>, PrepFunc>;
100 template <
typename... Args>
101 OpAwaiter(PrepFunc func, Args &&...args)
103 OpFinishHandle<CQEHandler>(std::forward<Args>(args)...)),
107template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler,
108 typename MultiShotFunc>
109class [[nodiscard]] MultiShotOpAwaiter
110 :
public OpAwaiterBase<MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>,
114 OpAwaiterBase<MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>,
116 template <
typename... Args>
117 MultiShotOpAwaiter(PrepFunc func, MultiShotFunc multishot_func,
119 : Base(HandleBox(MultiShotOpFinishHandle<CQEHandler, MultiShotFunc>(
120 std::move(multishot_func), std::forward<Args>(args)...)),
124template <PrepFuncLike PrepFunc, CQEHandlerLike CQEHandler,
typename FreeFunc>
125class [[nodiscard]] ZeroCopyOpAwaiter
126 :
public OpAwaiterBase<ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>,
130 OpAwaiterBase<ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>, PrepFunc>;
131 template <
typename... Args>
132 ZeroCopyOpAwaiter(PrepFunc func, FreeFunc free_func, Args &&...args)
133 : Base(HandleBox(ZeroCopyOpFinishHandle<CQEHandler, FreeFunc>(
134 std::move(free_func), std::forward<Args>(args)...)),
138template <
unsigned int Flags, AwaiterLike Awaiter>
139class [[nodiscard]] FlaggedOpAwaiter :
public Awaiter {
141 using Base = Awaiter;
142 FlaggedOpAwaiter(Awaiter awaiter) : Base(std::move(awaiter)) {}
144 void register_operation(
unsigned int flags) {
145#if IO_URING_CHECK_VERSION(2, 12)
146 if constexpr (Flags & IOSQE_IO_DRAIN) {
147 auto *runtime = detail::Context::current().runtime();
152 Base::register_operation(flags | Flags);
155 template <
typename PromiseType>
156 void await_suspend(std::coroutine_handle<PromiseType> h) {
157 Base::init_finish_handle();
158 Base::get_handle()->set_invoker(&h.promise());
159 register_operation(0);
163template <HandleLike Handle, AwaiterLike Awaiter>
164class [[nodiscard]] RangedParallelAwaiterBase {
166 using HandleType = Handle;
168 RangedParallelAwaiterBase(std::vector<Awaiter> awaiters)
169 : awaiters_(std::move(awaiters)) {}
170 RangedParallelAwaiterBase(RangedParallelAwaiterBase &&) =
default;
172 RangedParallelAwaiterBase(
const RangedParallelAwaiterBase &) =
delete;
173 RangedParallelAwaiterBase &
174 operator=(
const RangedParallelAwaiterBase &) =
delete;
175 RangedParallelAwaiterBase &operator=(RangedParallelAwaiterBase &&) =
delete;
178 HandleType *get_handle() {
return &finish_handle_; }
180 void init_finish_handle() {
181 using ChildHandle =
typename Awaiter::HandleType;
182 std::vector<ChildHandle *> handles;
183 handles.reserve(awaiters_.size());
184 for (
auto &awaiter : awaiters_) {
185 awaiter.init_finish_handle();
186 handles.push_back(awaiter.get_handle());
188 finish_handle_.init(std::move(handles));
191 void register_operation(
unsigned int flags) {
192 for (
auto &awaiter : awaiters_) {
193 awaiter.register_operation(flags);
198 bool await_ready() const noexcept {
return false; }
200 template <
typename PromiseType>
201 void await_suspend(std::coroutine_handle<PromiseType> h) {
202 init_finish_handle();
203 finish_handle_.set_invoker(&h.promise());
204 register_operation(0);
207 typename Handle::ReturnType await_resume() {
208 return finish_handle_.extract_result();
212 void push(Awaiter awaiter) { awaiters_.push_back(std::move(awaiter)); }
215 HandleType finish_handle_;
216 std::vector<Awaiter> awaiters_;
228template <
typename Awaiter>
230 RangedParallelAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
241template <
typename Awaiter>
243 RangedParallelAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
251template <
typename Awaiter>
253 RangedWhenAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
262template <
typename Awaiter>
264 RangedWhenAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
266template <
unsigned int Flags, AwaiterLike Awaiter>
267class [[nodiscard]] RangedLinkAwaiterBase
273 void register_operation(
unsigned int flags) {
274 auto *ring = detail::Context::current().ring();
275 ring->reserve_space(Base::awaiters_.size());
276 for (
int i = 0; i < Base::awaiters_.size() - 1; ++i) {
277 Base::awaiters_[i].register_operation(flags | Flags);
279 Base::awaiters_.back().register_operation(flags);
282 template <
typename PromiseType>
283 void await_suspend(std::coroutine_handle<PromiseType> h) {
284 Base::init_finish_handle();
285 Base::finish_handle_.set_invoker(&h.promise());
286 register_operation(0);
296template <
typename Awaiter>
306template <
typename Awaiter>
309template <HandleLike Handle, AwaiterLike... Awaiters>
310class [[nodiscard]] ParallelAwaiterBase {
312 using HandleType = Handle;
314 ParallelAwaiterBase(Awaiters... awaiters)
315 : awaiters_(std::move(awaiters)...) {}
316 ParallelAwaiterBase(ParallelAwaiterBase &&) =
default;
317 template <
typename ParallelAwaiter, AwaiterLike New>
318 ParallelAwaiterBase(ParallelAwaiter &&aws, New new_awaiter)
319 : awaiters_(std::tuple_cat(std::move(aws.awaiters_),
320 std::make_tuple(std::move(new_awaiter)))) {}
322 ParallelAwaiterBase(
const ParallelAwaiterBase &) =
delete;
323 ParallelAwaiterBase &operator=(
const ParallelAwaiterBase &) =
delete;
324 ParallelAwaiterBase &operator=(ParallelAwaiterBase &&) =
delete;
327 HandleType *get_handle() {
return &finish_handle_; }
329 void init_finish_handle() {
330 auto handles = foreach_init_finish_handle_();
331 static_assert(std::tuple_size<
decltype(handles)>::value ==
333 "Number of handles must match number of awaiters");
335 [
this](
auto &&...handle_ptrs) {
336 finish_handle_.init(handle_ptrs...);
341 void register_operation(
unsigned int flags) {
342 foreach_register_operation_(flags);
346 bool await_ready()
const noexcept {
return false; }
348 template <
typename PromiseType>
349 void await_suspend(std::coroutine_handle<PromiseType> h) {
350 init_finish_handle();
351 finish_handle_.set_invoker(&h.promise());
352 register_operation(0);
355 typename Handle::ReturnType await_resume() {
356 return finish_handle_.extract_result();
360 template <
size_t Idx = 0>
auto foreach_init_finish_handle_() {
361 if constexpr (Idx <
sizeof...(Awaiters)) {
362 std::get<Idx>(awaiters_).init_finish_handle();
363 return std::tuple_cat(
364 std::make_tuple(std::get<Idx>(awaiters_).get_handle()),
365 foreach_init_finish_handle_<Idx + 1>());
367 return std::tuple<>();
371 template <
size_t Idx = 0>
372 void foreach_register_operation_(
unsigned int flags) {
373 if constexpr (Idx <
sizeof...(Awaiters)) {
374 std::get<Idx>(awaiters_).register_operation(flags);
375 foreach_register_operation_<Idx + 1>(flags);
380 HandleType finish_handle_;
381 std::tuple<Awaiters...> awaiters_;
384 template <HandleLike, AwaiterLike...>
friend class ParallelAwaiterBase;
396template <
typename... Awaiter>
398 ParallelAllFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
409template <
typename... Awaiter>
411 ParallelAnyFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
419template <
typename... Awaiter>
421 ParallelAwaiterBase<WhenAllFinishHandle<
typename Awaiter::HandleType...>,
431template <
typename... Awaiter>
433 ParallelAwaiterBase<WhenAnyFinishHandle<
typename Awaiter::HandleType...>,
436template <
unsigned int Flags, AwaiterLike... Awaiter>
437class [[nodiscard]] LinkAwaiterBase :
public WhenAllAwaiter<Awaiter...> {
442 void register_operation(
unsigned int flags) {
443 auto *ring = detail::Context::current().ring();
444 ring->reserve_space(
sizeof...(Awaiter));
445 foreach_register_operation_(flags);
448 template <
typename PromiseType>
449 void await_suspend(std::coroutine_handle<PromiseType> h) {
450 Base::init_finish_handle();
451 Base::finish_handle_.set_invoker(&h.promise());
452 register_operation(0);
456 template <
size_t Idx = 0>
457 void foreach_register_operation_(
unsigned int flags) {
458 if constexpr (Idx <
sizeof...(Awaiter)) {
459 std::get<Idx>(Base::awaiters_)
460 .register_operation(Idx <
sizeof...(Awaiter) - 1 ? flags | Flags
462 foreach_register_operation_<Idx + 1>(flags);
473template <
typename... Awaiter>
482template <
typename... Awaiter>
Definitions of finish handle types for asynchronous operations.
The main namespace for the Condy library.
RangedParallelAwaiterBase< RangedParallelAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAllAwaiter
Awaiter to wait for all operations in a range to complete.
ParallelAwaiterBase< ParallelAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAllAwaiter
Awaiter to wait for all operations to complete in parallel.
RangedLinkAwaiterBase< IOSQE_IO_LINK, Awaiter > RangedLinkAwaiter
Awaiter that links multiple operations in a range using IO_LINK.
RangedParallelAwaiterBase< RangedWhenAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAnyAwaiter
Awaiter to wait for any operation in a range to complete.
RangedParallelAwaiterBase< RangedParallelAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAnyAwaiter
Awaiter to wait for any operation in a range to complete.
LinkAwaiterBase< IOSQE_IO_LINK, Awaiter... > LinkAwaiter
Awaiter that links multiple operations using IO_LINK.
RangedParallelAwaiterBase< RangedWhenAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAllAwaiter
Awaiter to wait for all operations in a range to complete.
ParallelAwaiterBase< WhenAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAllAwaiter
Awaiter that waits for all operations to complete in parallel.
ParallelAwaiterBase< WhenAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAnyAwaiter
Awaiter that waits for any operation to complete in parallel.
ParallelAwaiterBase< ParallelAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAnyAwaiter
Awaiter to wait for any operation to complete in parallel.
LinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter... > HardLinkAwaiter
Awaiter that links multiple operations using IO_HARDLINK.
RangedLinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter > RangedHardLinkAwaiter
Awaiter that links multiple operations in a range using IO_HARDLINK.
Wrapper classes for liburing interfaces.
Runtime type for running the io_uring event loop.