Condy v1.5.0
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
awaiter_operations.hpp
Go to the documentation of this file.
1
9
10#pragma once
11
12#include "condy/awaiters.hpp"
13#include "condy/concepts.hpp"
14#include "condy/cqe_handler.hpp"
15#include "condy/ring.hpp"
16
17namespace condy {
18
29template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc, typename... Args>
30auto build_op_awaiter(PrepFunc &&func, Args &&...handler_args) {
31 return OpAwaiter<std::decay_t<PrepFunc>, CQEHandler>(
32 std::forward<PrepFunc>(func), std::forward<Args>(handler_args)...);
33}
34
48template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc,
49 typename MultiShotFunc, typename... Args>
50auto build_multishot_op_awaiter(PrepFunc &&func, MultiShotFunc &&multishot_func,
51 Args &&...handler_args) {
52 return MultiShotOpAwaiter<std::decay_t<PrepFunc>, CQEHandler,
53 std::decay_t<MultiShotFunc>>(
54 std::forward<PrepFunc>(func),
55 std::forward<MultiShotFunc>(multishot_func),
56 std::forward<Args>(handler_args)...);
57}
58
71template <CQEHandlerLike CQEHandler, PrepFuncLike PrepFunc, typename FreeFunc,
72 typename... Args>
73auto build_zero_copy_op_awaiter(PrepFunc &&func, FreeFunc &&free_func,
74 Args &&...handler_args) {
75 return ZeroCopyOpAwaiter<std::decay_t<PrepFunc>, CQEHandler,
76 std::decay_t<FreeFunc>>(
77 std::forward<PrepFunc>(func), std::forward<FreeFunc>(free_func),
78 std::forward<Args>(handler_args)...);
79}
80
81namespace detail {
82
83template <typename Func, typename... Args>
84auto make_op_awaiter(Func &&func, Args &&...args) {
85 auto prep_func = [func = std::forward<Func>(func),
86 ... args = std::forward<Args>(args)](Ring *ring) {
87 auto *sqe = ring->get_sqe();
88 func(sqe, args...);
89 return sqe;
90 };
91 return build_op_awaiter<SimpleCQEHandler>(std::move(prep_func));
92}
93
94#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
95template <typename Func, typename... Args>
96auto make_op_awaiter128(Func &&func, Args &&...args) {
97 auto prep_func = [func = std::forward<Func>(func),
98 ... args = std::forward<Args>(args)](Ring *ring) {
99 auto *sqe = ring->get_sqe128();
100 func(sqe, args...);
101 return sqe;
102 };
103 return build_op_awaiter<SimpleCQEHandler>(std::move(prep_func));
104}
105#endif
106
107template <typename MultiShotFunc, typename Func, typename... Args>
108auto make_multishot_op_awaiter(MultiShotFunc &&multishot_func, Func &&func,
109 Args &&...args) {
110 auto prep_func = [func = std::forward<Func>(func),
111 ... args = std::forward<Args>(args)](Ring *ring) {
112 auto *sqe = ring->get_sqe();
113 func(sqe, args...);
114 return sqe;
115 };
117 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func));
118}
119
120template <BufferRingLike Br, typename Func, typename... Args>
121auto make_select_buffer_op_awaiter(Br *buffers, Func &&func, Args &&...args) {
122 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
123 ... args = std::forward<Args>(args)](Ring *ring) {
124 auto *sqe = ring->get_sqe();
125 func(sqe, args...);
126 sqe->flags |= IOSQE_BUFFER_SELECT;
127 sqe->buf_group = bgid;
128 return sqe;
129 };
130 return build_op_awaiter<SelectBufferCQEHandler<Br>>(std::move(prep_func),
131 buffers);
132}
133
134template <typename MultiShotFunc, BufferRingLike Br, typename Func,
135 typename... Args>
136auto make_multishot_select_buffer_op_awaiter(MultiShotFunc &&multishot_func,
137 Br *buffers, Func &&func,
138 Args &&...args) {
139 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
140 ... args = std::forward<Args>(args)](Ring *ring) {
141 auto *sqe = ring->get_sqe();
142 func(sqe, args...);
143 sqe->flags |= IOSQE_BUFFER_SELECT;
144 sqe->buf_group = bgid;
145 return sqe;
146 };
148 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func),
149 buffers);
150}
151
152#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
153template <BufferRingLike Br, typename Func, typename... Args>
154auto make_bundle_select_buffer_op_awaiter(Br *buffers, Func &&func,
155 Args &&...args) {
156 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
157 ... args = std::forward<Args>(args)](Ring *ring) {
158 auto *sqe = ring->get_sqe();
159 func(sqe, args...);
160 sqe->flags |= IOSQE_BUFFER_SELECT;
161 sqe->buf_group = bgid;
162 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
163 return sqe;
164 };
165 return build_op_awaiter<SelectBufferCQEHandler<Br>>(std::move(prep_func),
166 buffers);
167}
168#endif
169
170#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
171template <typename MultiShotFunc, BufferRingLike Br, typename Func,
172 typename... Args>
173auto make_multishot_bundle_select_buffer_op_awaiter(
174 MultiShotFunc &&multishot_func, Br *buffers, Func &&func, Args &&...args) {
175 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
176 ... args = std::forward<Args>(args)](Ring *ring) {
177 auto *sqe = ring->get_sqe();
178 func(sqe, args...);
179 sqe->flags |= IOSQE_BUFFER_SELECT;
180 sqe->buf_group = bgid;
181 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
182 return sqe;
183 };
185 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func),
186 buffers);
187}
188#endif
189
190template <typename FreeFunc, typename Func, typename... Args>
191auto make_zero_copy_op_awaiter(FreeFunc &&free_func, Func &&func,
192 Args &&...args) {
193 auto prep_func = [func = std::forward<Func>(func),
194 ... args = std::forward<Args>(args)](Ring *ring) {
195 auto *sqe = ring->get_sqe();
196 func(sqe, args...);
197 return sqe;
198 };
200 std::move(prep_func), std::forward<FreeFunc>(free_func));
201}
202
203} // namespace detail
204
211template <unsigned int Flags, AwaiterLike Awaiter>
212auto flag(Awaiter &&awaiter) {
213 return FlaggedOpAwaiter<Flags, std::decay_t<Awaiter>>(
214 std::forward<Awaiter>(awaiter));
215}
216
221template <AwaiterLike Awaiter> auto drain(Awaiter &&awaiter) {
222 return flag<IOSQE_IO_DRAIN>(std::forward<Awaiter>(awaiter));
223}
224
229template <AwaiterLike Awaiter> auto always_async(Awaiter &&awaiter) {
230 return flag<IOSQE_ASYNC>(std::forward<Awaiter>(awaiter));
231}
232
241template <template <AwaiterLike... Awaiter> typename AwaiterType,
242 AwaiterLike... Awaiter>
243auto parallel(Awaiter &&...awaiters) {
244 return AwaiterType<std::decay_t<Awaiter>...>(
245 std::forward<Awaiter>(awaiters)...);
246}
247
256template <template <typename Awaiter> typename RangedAwaiterType,
257 AwaiterRange Range>
258auto parallel(Range &&range) {
259 using AwaiterType = typename std::decay_t<Range>::value_type;
260 auto begin = std::make_move_iterator(std::begin(range));
261 auto end = std::make_move_iterator(std::end(range));
262 std::vector<AwaiterType> awaiters(begin, end);
263 return RangedAwaiterType<AwaiterType>(std::move(awaiters));
264}
265
273template <AwaiterLike... Awaiters> auto when_all(Awaiters &&...awaiters) {
274 return parallel<WhenAllAwaiter>(std::forward<Awaiters>(awaiters)...);
275}
276
284template <AwaiterRange Range> auto when_all(Range &&range) {
285 return parallel<RangedWhenAllAwaiter>(std::forward<Range>(range));
286}
287
297template <AwaiterLike... Awaiters> auto when_any(Awaiters &&...awaiters) {
298 return parallel<WhenAnyAwaiter>(std::forward<Awaiters>(awaiters)...);
299}
300
308template <AwaiterRange Range> auto when_any(Range &&range) {
309 return parallel<RangedWhenAnyAwaiter>(std::forward<Range>(range));
310}
311
319template <AwaiterLike... Awaiters> auto link(Awaiters &&...awaiters) {
320 return parallel<LinkAwaiter>(std::forward<Awaiters>(awaiters)...);
321}
322
330template <AwaiterRange Range> auto link(Range &&range) {
331 return parallel<RangedLinkAwaiter>(std::forward<Range>(range));
332}
333
341template <AwaiterLike... Awaiters> auto hard_link(Awaiters &&...awaiters) {
342 return parallel<HardLinkAwaiter>(std::forward<Awaiters>(awaiters)...);
343}
344
352template <AwaiterRange Range> auto hard_link(Range &&range) {
353 return parallel<RangedHardLinkAwaiter>(std::forward<Range>(range));
354}
355
359namespace operators {
360
364template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
365auto operator&&(Awaiter1 aw1, Awaiter2 aw2) {
366 return when_all(std::move(aw1), std::move(aw2));
367}
368
372template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
374 return WhenAllAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
375 std::move(aw));
376}
377
381template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
382auto operator||(Awaiter1 aw1, Awaiter2 aw2) {
383 return when_any(std::move(aw1), std::move(aw2));
384}
385
389template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
391 return WhenAnyAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
392 std::move(aw));
393}
394
398template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
399auto operator>>(Awaiter1 aw1, Awaiter2 aw2) {
400 return link(std::move(aw1), std::move(aw2));
401}
402
406template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
408 return LinkAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
409 std::move(aw));
410}
411
412} // namespace operators
413
414} // namespace condy
Definitions of awaiter types for asynchronous operations.
Definitions of CQE handlers.
Operators for composing awaiters.
auto operator||(Awaiter1 aw1, Awaiter2 aw2)
Operator overloads version of when_any.
auto operator&&(Awaiter1 aw1, Awaiter2 aw2)
Operator overloads version of when_all.
auto operator>>(Awaiter1 aw1, Awaiter2 aw2)
Operator overloads version of link.
The main namespace for the Condy library.
Definition condy.hpp:28
auto parallel(Awaiter &&...awaiters)
Compose multiple awaiters into a single awaiter that executes them in parallel.
auto build_op_awaiter(PrepFunc &&func, Args &&...handler_args)
Build a single-shot operation awaiter with custom CQE handler.
auto drain(Awaiter &&awaiter)
Mark an awaiter as drain operation.
auto build_zero_copy_op_awaiter(PrepFunc &&func, FreeFunc &&free_func, Args &&...handler_args)
Build a zero-copy operation awaiter with custom CQE handler.
auto build_multishot_op_awaiter(PrepFunc &&func, MultiShotFunc &&multishot_func, Args &&...handler_args)
Build a multi-shot operation awaiter with custom CQE handler.
auto when_all(Awaiters &&...awaiters)
Compose multiple awaiters into a single awaiter that completes when all of them complete.
auto link(Awaiters &&...awaiters)
Compose multiple awaiters into a single awaiter that executes them in sequence.
LinkAwaiterBase< IOSQE_IO_LINK, Awaiter... > LinkAwaiter
Awaiter that links multiple operations using IO_LINK.
Definition awaiters.hpp:463
auto when_any(Awaiters &&...awaiters)
Compose multiple awaiters into a single awaiter that completes when any of them complete.
auto flag(Awaiter &&awaiter)
Decorates an awaiter with specific io_uring sqe flags.
ParallelAwaiterBase< WhenAllFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAllAwaiter
Awaiter that waits for all operations to complete in parallel.
Definition awaiters.hpp:409
auto hard_link(Awaiters &&...awaiters)
Compose multiple awaiters into a single awaiter that executes them in sequence and continues even if ...
ParallelAwaiterBase< WhenAnyFinishHandle< typename Awaiter::HandleType... >, Awaiter... > WhenAnyAwaiter
Awaiter that waits for any operation to complete in parallel.
Definition awaiters.hpp:421
auto always_async(Awaiter &&awaiter)
Mark an awaiter to always execute asynchronously.
Wrapper classes for liburing interfaces.