Condy v1.6.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 if (!sqe) {
101 panic_on("SQE128 not enabled in the ring");
102 }
103 func(sqe, args...);
104 return sqe;
105 };
106 return build_op_awaiter<SimpleCQEHandler>(std::move(prep_func));
107}
108#endif
109
110template <typename MultiShotFunc, typename Func, typename... Args>
111auto make_multishot_op_awaiter(MultiShotFunc &&multishot_func, Func &&func,
112 Args &&...args) {
113 auto prep_func = [func = std::forward<Func>(func),
114 ... args = std::forward<Args>(args)](Ring *ring) {
115 auto *sqe = ring->get_sqe();
116 func(sqe, args...);
117 return sqe;
118 };
120 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func));
121}
122
123template <BufferRingLike Br, typename Func, typename... Args>
124auto make_select_buffer_op_awaiter(Br *buffers, Func &&func, Args &&...args) {
125 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
126 ... args = std::forward<Args>(args)](Ring *ring) {
127 auto *sqe = ring->get_sqe();
128 func(sqe, args...);
129 sqe->flags |= IOSQE_BUFFER_SELECT;
130 sqe->buf_group = bgid;
131 return sqe;
132 };
133 return build_op_awaiter<SelectBufferCQEHandler<Br>>(std::move(prep_func),
134 buffers);
135}
136
137template <typename MultiShotFunc, BufferRingLike Br, typename Func,
138 typename... Args>
139auto make_multishot_select_buffer_op_awaiter(MultiShotFunc &&multishot_func,
140 Br *buffers, Func &&func,
141 Args &&...args) {
142 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
143 ... args = std::forward<Args>(args)](Ring *ring) {
144 auto *sqe = ring->get_sqe();
145 func(sqe, args...);
146 sqe->flags |= IOSQE_BUFFER_SELECT;
147 sqe->buf_group = bgid;
148 return sqe;
149 };
151 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func),
152 buffers);
153}
154
155#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
156template <BufferRingLike Br, typename Func, typename... Args>
157auto make_bundle_select_buffer_op_awaiter(Br *buffers, Func &&func,
158 Args &&...args) {
159 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
160 ... args = std::forward<Args>(args)](Ring *ring) {
161 auto *sqe = ring->get_sqe();
162 func(sqe, args...);
163 sqe->flags |= IOSQE_BUFFER_SELECT;
164 sqe->buf_group = bgid;
165 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
166 return sqe;
167 };
168 return build_op_awaiter<SelectBufferCQEHandler<Br>>(std::move(prep_func),
169 buffers);
170}
171#endif
172
173#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
174template <typename MultiShotFunc, BufferRingLike Br, typename Func,
175 typename... Args>
176auto make_multishot_bundle_select_buffer_op_awaiter(
177 MultiShotFunc &&multishot_func, Br *buffers, Func &&func, Args &&...args) {
178 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
179 ... args = std::forward<Args>(args)](Ring *ring) {
180 auto *sqe = ring->get_sqe();
181 func(sqe, args...);
182 sqe->flags |= IOSQE_BUFFER_SELECT;
183 sqe->buf_group = bgid;
184 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
185 return sqe;
186 };
188 std::move(prep_func), std::forward<MultiShotFunc>(multishot_func),
189 buffers);
190}
191#endif
192
193template <typename FreeFunc, typename Func, typename... Args>
194auto make_zero_copy_op_awaiter(FreeFunc &&free_func, Func &&func,
195 Args &&...args) {
196 auto prep_func = [func = std::forward<Func>(func),
197 ... args = std::forward<Args>(args)](Ring *ring) {
198 auto *sqe = ring->get_sqe();
199 func(sqe, args...);
200 return sqe;
201 };
203 std::move(prep_func), std::forward<FreeFunc>(free_func));
204}
205
206} // namespace detail
207
214template <unsigned int Flags, AwaiterLike Awaiter>
215auto flag(Awaiter &&awaiter) {
216 return FlaggedOpAwaiter<Flags, std::decay_t<Awaiter>>(
217 std::forward<Awaiter>(awaiter));
218}
219
224template <AwaiterLike Awaiter> auto drain(Awaiter &&awaiter) {
225 return flag<IOSQE_IO_DRAIN>(std::forward<Awaiter>(awaiter));
226}
227
232template <AwaiterLike Awaiter> auto always_async(Awaiter &&awaiter) {
233 return flag<IOSQE_ASYNC>(std::forward<Awaiter>(awaiter));
234}
235
244template <template <AwaiterLike... Awaiter> typename AwaiterType,
245 AwaiterLike... Awaiter>
246auto parallel(Awaiter &&...awaiters) {
247 return AwaiterType<std::decay_t<Awaiter>...>(
248 std::forward<Awaiter>(awaiters)...);
249}
250
259template <template <typename Awaiter> typename RangedAwaiterType,
260 AwaiterRange Range>
261auto parallel(Range &&range) {
262 using AwaiterType = typename std::decay_t<Range>::value_type;
263 auto begin = std::make_move_iterator(std::begin(range));
264 auto end = std::make_move_iterator(std::end(range));
265 std::vector<AwaiterType> awaiters(begin, end);
266 return RangedAwaiterType<AwaiterType>(std::move(awaiters));
267}
268
276template <AwaiterLike... Awaiters> auto when_all(Awaiters &&...awaiters) {
277 return parallel<WhenAllAwaiter>(std::forward<Awaiters>(awaiters)...);
278}
279
287template <AwaiterRange Range> auto when_all(Range &&range) {
288 return parallel<RangedWhenAllAwaiter>(std::forward<Range>(range));
289}
290
300template <AwaiterLike... Awaiters> auto when_any(Awaiters &&...awaiters) {
301 return parallel<WhenAnyAwaiter>(std::forward<Awaiters>(awaiters)...);
302}
303
311template <AwaiterRange Range> auto when_any(Range &&range) {
312 return parallel<RangedWhenAnyAwaiter>(std::forward<Range>(range));
313}
314
322template <AwaiterLike... Awaiters> auto link(Awaiters &&...awaiters) {
323 return parallel<LinkAwaiter>(std::forward<Awaiters>(awaiters)...);
324}
325
333template <AwaiterRange Range> auto link(Range &&range) {
334 return parallel<RangedLinkAwaiter>(std::forward<Range>(range));
335}
336
344template <AwaiterLike... Awaiters> auto hard_link(Awaiters &&...awaiters) {
345 return parallel<HardLinkAwaiter>(std::forward<Awaiters>(awaiters)...);
346}
347
355template <AwaiterRange Range> auto hard_link(Range &&range) {
356 return parallel<RangedHardLinkAwaiter>(std::forward<Range>(range));
357}
358
362namespace operators {
363
367template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
368auto operator&&(Awaiter1 aw1, Awaiter2 aw2) {
369 return when_all(std::move(aw1), std::move(aw2));
370}
371
375template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
377 return WhenAllAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
378 std::move(aw));
379}
380
384template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
385auto operator||(Awaiter1 aw1, Awaiter2 aw2) {
386 return when_any(std::move(aw1), std::move(aw2));
387}
388
392template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
394 return WhenAnyAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
395 std::move(aw));
396}
397
401template <AwaiterLike Awaiter1, AwaiterLike Awaiter2>
402auto operator>>(Awaiter1 aw1, Awaiter2 aw2) {
403 return link(std::move(aw1), std::move(aw2));
404}
405
409template <AwaiterLike Awaiter, AwaiterLike... Awaiters>
411 return LinkAwaiter<Awaiters..., std::decay_t<Awaiter>>(std::move(aws),
412 std::move(aw));
413}
414
415} // namespace operators
416
417} // 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:30
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:450
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:393
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:405
auto always_async(Awaiter &&awaiter)
Mark an awaiter to always execute asynchronously.
Wrapper classes for liburing interfaces.