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,
typename 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 = Context::current();
67 auto *ring = context.ring();
69 context.runtime()->pend_work();
70 io_uring_sqe *sqe = ring->get_sqe();
75 bool await_ready() {
return false; }
77 template <
typename PromiseType>
78 void await_suspend(std::coroutine_handle<PromiseType> h) {
80 finish_handle_.get().set_invoker(&h.promise());
81 register_operation(0);
84 auto await_resume() {
return finish_handle_.get().extract_result(); }
87 void prep_op_(io_uring_sqe *sqe,
unsigned int flags) {
89 sqe->flags |=
static_cast<uint8_t
>(flags);
90 io_uring_sqe_set_data(
91 sqe, encode_work(&finish_handle_.get(), Handle::work_type));
92 sqe->personality = Context::current().cred_id();
97 HandleBox<Handle> finish_handle_;
100template <
typename Func>
101class [[nodiscard]] OpAwaiter :
public OpAwaiterBase<OpFinishHandle, Func> {
103 using Base = OpAwaiterBase<OpFinishHandle, Func>;
104 OpAwaiter(Func func) : Base(OpFinishHandle(), func) {}
107template <
typename MultiShotFunc,
typename Func>
108class [[nodiscard]] MultiShotOpAwaiter
109 :
public OpAwaiterBase<MultiShotOpFinishHandle<MultiShotFunc>, Func> {
111 using Base = OpAwaiterBase<MultiShotOpFinishHandle<MultiShotFunc>, Func>;
112 MultiShotOpAwaiter(MultiShotFunc multishot_func, Func func)
114 MultiShotOpFinishHandle<MultiShotFunc>(std::move(multishot_func)),
118template <
typename FreeFunc,
typename Func>
119class [[nodiscard]] ZeroCopyOpAwaiter
120 :
public OpAwaiterBase<ZeroCopyOpFinishHandle<FreeFunc>, Func> {
122 using Base = OpAwaiterBase<ZeroCopyOpFinishHandle<FreeFunc>, Func>;
123 ZeroCopyOpAwaiter(FreeFunc free_func, Func func)
124 : Base(ZeroCopyOpFinishHandle<FreeFunc>(std::move(free_func)), func) {}
127template <BufferRingLike Br,
typename Func>
128class [[nodiscard]] SelectBufferOpAwaiter
129 :
public OpAwaiterBase<SelectBufferOpFinishHandle<Br>, Func> {
131 using Base = OpAwaiterBase<SelectBufferOpFinishHandle<Br>, Func>;
132 SelectBufferOpAwaiter(Br *buffers, Func func)
133 : Base(SelectBufferOpFinishHandle<Br>(buffers), func) {}
136template <
typename MultiShotFunc, BufferRingLike Br,
typename Func>
137class [[nodiscard]] MultiShotSelectBufferOpAwaiter
138 :
public OpAwaiterBase<
139 MultiShotSelectBufferOpFinishHandle<MultiShotFunc, Br>, Func> {
142 OpAwaiterBase<MultiShotSelectBufferOpFinishHandle<MultiShotFunc, Br>,
144 MultiShotSelectBufferOpAwaiter(MultiShotFunc multishot_func, Br *buffers,
146 : Base(MultiShotSelectBufferOpFinishHandle<MultiShotFunc, Br>(
147 std::move(multishot_func), buffers),
151template <
unsigned int Flags, AwaiterLike Awaiter>
152class [[nodiscard]] FlaggedOpAwaiter :
public Awaiter {
154 using Base = Awaiter;
155 FlaggedOpAwaiter(Awaiter awaiter) : Base(std::move(awaiter)) {}
157 void register_operation(
unsigned int flags) {
158#if IO_URING_CHECK_VERSION(2, 12)
159 if constexpr (Flags & IOSQE_IO_DRAIN) {
160 auto *runtime = Context::current().runtime();
165 Base::register_operation(flags | Flags);
168 template <
typename PromiseType>
169 void await_suspend(std::coroutine_handle<PromiseType> h) {
170 Base::init_finish_handle();
171 Base::get_handle()->set_invoker(&h.promise());
172 register_operation(0);
176template <HandleLike Handle, AwaiterLike Awaiter>
177class [[nodiscard]] RangedParallelAwaiterBase {
179 using HandleType = Handle;
181 RangedParallelAwaiterBase(std::vector<Awaiter> awaiters)
182 : awaiters_(std::move(awaiters)) {}
183 RangedParallelAwaiterBase(RangedParallelAwaiterBase &&) =
default;
185 RangedParallelAwaiterBase(
const RangedParallelAwaiterBase &) =
delete;
186 RangedParallelAwaiterBase &
187 operator=(
const RangedParallelAwaiterBase &) =
delete;
188 RangedParallelAwaiterBase &operator=(RangedParallelAwaiterBase &&) =
delete;
191 HandleType *get_handle() {
return &finish_handle_; }
193 void init_finish_handle() {
194 using ChildHandle =
typename Awaiter::HandleType;
195 std::vector<ChildHandle *> handles;
196 handles.reserve(awaiters_.size());
197 for (
auto &awaiter : awaiters_) {
198 awaiter.init_finish_handle();
199 handles.push_back(awaiter.get_handle());
201 finish_handle_.init(std::move(handles));
204 void register_operation(
unsigned int flags) {
205 for (
auto &awaiter : awaiters_) {
206 awaiter.register_operation(flags);
211 bool await_ready() const noexcept {
return false; }
213 template <
typename PromiseType>
214 void await_suspend(std::coroutine_handle<PromiseType> h) {
215 init_finish_handle();
216 finish_handle_.set_invoker(&h.promise());
217 register_operation(0);
220 typename Handle::ReturnType await_resume() {
221 return finish_handle_.extract_result();
225 void push(Awaiter awaiter) { awaiters_.push_back(std::move(awaiter)); }
228 HandleType finish_handle_;
229 std::vector<Awaiter> awaiters_;
241template <
typename Awaiter>
243 RangedParallelAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
254template <
typename Awaiter>
256 RangedParallelAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
264template <
typename Awaiter>
266 RangedWhenAllFinishHandle<typename Awaiter::HandleType>, Awaiter>;
275template <
typename Awaiter>
277 RangedWhenAnyFinishHandle<typename Awaiter::HandleType>, Awaiter>;
279template <
unsigned int Flags, AwaiterLike Awaiter>
280class [[nodiscard]] RangedLinkAwaiterBase
286 void register_operation(
unsigned int flags) {
287 auto *ring = Context::current().ring();
288 ring->reserve_space(Base::awaiters_.size());
289 for (
int i = 0; i < Base::awaiters_.size() - 1; ++i) {
290 Base::awaiters_[i].register_operation(flags | Flags);
292 Base::awaiters_.back().register_operation(flags);
295 template <
typename PromiseType>
296 void await_suspend(std::coroutine_handle<PromiseType> h) {
297 Base::init_finish_handle();
298 Base::finish_handle_.set_invoker(&h.promise());
299 register_operation(0);
309template <
typename Awaiter>
319template <
typename Awaiter>
322template <HandleLike Handle, AwaiterLike... Awaiters>
323class [[nodiscard]] ParallelAwaiterBase {
325 using HandleType = Handle;
327 ParallelAwaiterBase(Awaiters... awaiters)
328 : awaiters_(std::move(awaiters)...) {}
329 ParallelAwaiterBase(ParallelAwaiterBase &&) =
default;
330 template <
typename ParallelAwaiter, AwaiterLike New>
331 ParallelAwaiterBase(ParallelAwaiter &&aws, New new_awaiter)
332 : awaiters_(std::tuple_cat(std::move(aws.awaiters_),
333 std::make_tuple(std::move(new_awaiter)))) {}
335 ParallelAwaiterBase(
const ParallelAwaiterBase &) =
delete;
336 ParallelAwaiterBase &operator=(
const ParallelAwaiterBase &) =
delete;
337 ParallelAwaiterBase &operator=(ParallelAwaiterBase &&) =
delete;
340 HandleType *get_handle() {
return &finish_handle_; }
342 void init_finish_handle() {
343 auto handles = foreach_init_finish_handle_();
344 static_assert(std::tuple_size<
decltype(handles)>::value ==
346 "Number of handles must match number of awaiters");
348 [
this](
auto &&...handle_ptrs) {
349 finish_handle_.init(handle_ptrs...);
354 void register_operation(
unsigned int flags) {
355 foreach_register_operation_(flags);
359 bool await_ready()
const noexcept {
return false; }
361 template <
typename PromiseType>
362 void await_suspend(std::coroutine_handle<PromiseType> h) {
363 init_finish_handle();
364 finish_handle_.set_invoker(&h.promise());
365 register_operation(0);
368 typename Handle::ReturnType await_resume() {
369 return finish_handle_.extract_result();
373 template <
size_t Idx = 0>
auto foreach_init_finish_handle_() {
374 if constexpr (Idx <
sizeof...(Awaiters)) {
375 std::get<Idx>(awaiters_).init_finish_handle();
376 return std::tuple_cat(
377 std::make_tuple(std::get<Idx>(awaiters_).get_handle()),
378 foreach_init_finish_handle_<Idx + 1>());
380 return std::tuple<>();
384 template <
size_t Idx = 0>
385 void foreach_register_operation_(
unsigned int flags) {
386 if constexpr (Idx <
sizeof...(Awaiters)) {
387 std::get<Idx>(awaiters_).register_operation(flags);
388 foreach_register_operation_<Idx + 1>(flags);
393 HandleType finish_handle_;
394 std::tuple<Awaiters...> awaiters_;
397 template <HandleLike, AwaiterLike...>
friend class ParallelAwaiterBase;
409template <
typename... Awaiter>
411 ParallelAllFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
422template <
typename... Awaiter>
424 ParallelAnyFinishHandle<
typename Awaiter::HandleType...>, Awaiter...>;
432template <
typename... Awaiter>
434 ParallelAwaiterBase<WhenAllFinishHandle<
typename Awaiter::HandleType...>,
444template <
typename... Awaiter>
446 ParallelAwaiterBase<WhenAnyFinishHandle<
typename Awaiter::HandleType...>,
449template <
unsigned int Flags, AwaiterLike... Awaiter>
450class [[nodiscard]] LinkAwaiterBase :
public WhenAllAwaiter<Awaiter...> {
455 void register_operation(
unsigned int flags) {
456 auto *ring = Context::current().ring();
457 ring->reserve_space(
sizeof...(Awaiter));
458 foreach_register_operation_(flags);
461 template <
typename PromiseType>
462 void await_suspend(std::coroutine_handle<PromiseType> h) {
463 Base::init_finish_handle();
464 Base::finish_handle_.set_invoker(&h.promise());
465 register_operation(0);
469 template <
size_t Idx = 0>
470 void foreach_register_operation_(
unsigned int flags) {
471 if constexpr (Idx <
sizeof...(Awaiter)) {
472 std::get<Idx>(Base::awaiters_)
473 .register_operation(Idx <
sizeof...(Awaiter) - 1 ? flags | Flags
475 foreach_register_operation_<Idx + 1>(flags);
486template <
typename... Awaiter>
495template <
typename... Awaiter>
Definitions of finish handle types for asynchronous operations.
The main namespace for the Condy library.
Definition condy.hpp:28
RangedParallelAwaiterBase< RangedParallelAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAllAwaiter
Awaiter to wait for all operations in a range to complete.
Definition awaiters.hpp:242
ParallelAwaiterBase< ParallelAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAllAwaiter
Awaiter to wait for all operations to complete in parallel.
Definition awaiters.hpp:410
RangedLinkAwaiterBase< IOSQE_IO_LINK, Awaiter > RangedLinkAwaiter
Awaiter that links multiple operations in a range using IO_LINK.
Definition awaiters.hpp:310
RangedParallelAwaiterBase< RangedWhenAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAnyAwaiter
Awaiter to wait for any operation in a range to complete.
Definition awaiters.hpp:276
RangedParallelAwaiterBase< RangedParallelAnyFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedParallelAnyAwaiter
Awaiter to wait for any operation in a range to complete.
Definition awaiters.hpp:255
LinkAwaiterBase< IOSQE_IO_LINK, Awaiter... > LinkAwaiter
Awaiter that links multiple operations using IO_LINK.
Definition awaiters.hpp:487
RangedParallelAwaiterBase< RangedWhenAllFinishHandle< typename Awaiter::HandleType >, Awaiter > RangedWhenAllAwaiter
Awaiter to wait for all operations in a range to complete.
Definition awaiters.hpp:265
ParallelAwaiterBase< WhenAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAllAwaiter
Awaiter that waits for all operations to complete in parallel.
Definition awaiters.hpp:433
ParallelAwaiterBase< WhenAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAnyAwaiter
Awaiter that waits for any operation to complete in parallel.
Definition awaiters.hpp:445
ParallelAwaiterBase< ParallelAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > ParallelAnyAwaiter
Awaiter to wait for any operation to complete in parallel.
Definition awaiters.hpp:423
LinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter... > HardLinkAwaiter
Awaiter that links multiple operations using IO_HARDLINK.
Definition awaiters.hpp:496
RangedLinkAwaiterBase< IOSQE_IO_HARDLINK, Awaiter > RangedHardLinkAwaiter
Awaiter that links multiple operations in a range using IO_HARDLINK.
Definition awaiters.hpp:320
Wrapper classes for liburing interfaces.
Runtime type for running the io_uring event loop.