Condy v1.9
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
async_operations.hpp
Go to the documentation of this file.
1
8
9#pragma once
10
12#include "condy/concepts.hpp"
13#include "condy/condy_uring.hpp"
14#include "condy/cqe_handler.hpp"
16
17namespace condy {
18namespace detail {
19
20template <typename T> T &&unwrap_fixed(T &&t) noexcept {
21 return std::forward<T>(t);
22}
23
24inline int unwrap_fixed(FixedFd fd) noexcept { return fd.value; }
25
26template <typename Func, typename... Args>
27auto make_op_awaiter(Func &&func, Args &&...args) {
28 auto prep_func = [func = std::forward<Func>(func),
29 ... args =
30 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
31 auto *sqe = ring->get_sqe();
32 func(sqe, args...);
33 return sqe;
34 };
35 return build_op_awaiter(std::move(prep_func), SimpleCQEHandler{});
36}
37
38#if CONDY_URING_VERSION_GE(2, 13) // >= 2.13
39template <typename Func, typename... Args>
40auto make_op_awaiter128(Func &&func, Args &&...args) {
41 auto prep_func = [func = std::forward<Func>(func),
42 ... args =
43 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
44 auto *sqe = ring->get_sqe128();
45 if (sqe) {
46 func(sqe, args...);
47 }
48 return sqe;
49 };
50 return build_op_awaiter(std::move(prep_func), SimpleCQEHandler{});
51}
52#endif
53
54template <typename MultiShotFunc, typename Func, typename... Args>
55auto make_multishot_op_awaiter(MultiShotFunc &&multishot_func, Func &&func,
56 Args &&...args) {
57 auto prep_func = [func = std::forward<Func>(func),
58 ... args =
59 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
60 auto *sqe = ring->get_sqe();
61 func(sqe, args...);
62 return sqe;
63 };
65 std::move(prep_func), SimpleCQEHandler{},
66 std::forward<MultiShotFunc>(multishot_func));
67}
68
69template <BufferRingLike Br, typename Func, typename... Args>
70auto make_select_buffer_op_awaiter(Br *buffers, Func &&func, Args &&...args) {
71 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
72 ... args =
73 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
74 auto *sqe = ring->get_sqe();
75 func(sqe, args...);
76 sqe->flags |= IOSQE_BUFFER_SELECT;
77 sqe->buf_group = bgid;
78 return sqe;
79 };
80 return build_op_awaiter(std::move(prep_func),
81 SelectBufferCQEHandler<Br>(buffers));
82}
83
84template <typename MultiShotFunc, BufferRingLike Br, typename Func,
85 typename... Args>
86auto make_multishot_select_buffer_op_awaiter(MultiShotFunc &&multishot_func,
87 Br *buffers, Func &&func,
88 Args &&...args) {
89 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
90 ... args =
91 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
92 auto *sqe = ring->get_sqe();
93 func(sqe, args...);
94 sqe->flags |= IOSQE_BUFFER_SELECT;
95 sqe->buf_group = bgid;
96 return sqe;
97 };
99 std::move(prep_func), SelectBufferCQEHandler<Br>(buffers),
100 std::forward<MultiShotFunc>(multishot_func));
101}
102
103#if CONDY_URING_VERSION_GE(2, 7) // >= 2.7
104template <BufferRingLike Br, typename Func, typename... Args>
105auto make_bundle_select_buffer_op_awaiter(Br *buffers, Func &&func,
106 Args &&...args) {
107 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
108 ... args =
109 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
110 auto *sqe = ring->get_sqe();
111 func(sqe, args...);
112 sqe->flags |= IOSQE_BUFFER_SELECT;
113 sqe->buf_group = bgid;
114 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
115 return sqe;
116 };
117 return build_op_awaiter(std::move(prep_func),
118 SelectBufferCQEHandler<Br>(buffers));
119}
120#endif
121
122#if CONDY_URING_VERSION_GE(2, 7) // >= 2.7
123template <typename MultiShotFunc, BufferRingLike Br, typename Func,
124 typename... Args>
125auto make_multishot_bundle_select_buffer_op_awaiter(
126 MultiShotFunc &&multishot_func, Br *buffers, Func &&func, Args &&...args) {
127 auto prep_func = [bgid = buffers->bgid(), func = std::forward<Func>(func),
128 ... args =
129 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
130 auto *sqe = ring->get_sqe();
131 func(sqe, args...);
132 sqe->flags |= IOSQE_BUFFER_SELECT;
133 sqe->buf_group = bgid;
134 sqe->ioprio |= IORING_RECVSEND_BUNDLE;
135 return sqe;
136 };
138 std::move(prep_func), SelectBufferCQEHandler<Br>(buffers),
139 std::forward<MultiShotFunc>(multishot_func));
140}
141#endif
142
143template <typename FreeFunc, typename Func, typename... Args>
144auto make_zero_copy_op_awaiter(FreeFunc &&free_func, Func &&func,
145 Args &&...args) {
146 auto prep_func = [func = std::forward<Func>(func),
147 ... args =
148 unwrap_fixed(std::forward<Args>(args))](Ring *ring) {
149 auto *sqe = ring->get_sqe();
150 func(sqe, args...);
151 return sqe;
152 };
153 return build_zero_copy_op_awaiter(std::move(prep_func), SimpleCQEHandler{},
154 std::forward<FreeFunc>(free_func));
155}
156
157template <typename Awaiter>
158auto maybe_flag_fixed_fd(Awaiter &&op, const FixedFd &) {
159 return flag<IOSQE_FIXED_FILE>(std::forward<Awaiter>(op));
160}
161
162template <typename Awaiter> auto maybe_flag_fixed_fd(Awaiter &&op, int) {
163 return std::forward<Awaiter>(op);
164}
165
166template <typename Fd>
167constexpr bool is_fixed_fd_v = std::is_same_v<std::remove_cvref_t<Fd>, FixedFd>;
168
169inline void prep_send_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
170 size_t len, int flags, int buf_index) noexcept {
171 io_uring_prep_send(sqe, sockfd, buf, len, flags);
172 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
173 sqe->buf_index = buf_index;
174}
175
176inline void prep_recv_fixed(io_uring_sqe *sqe, int sockfd, void *buf,
177 size_t len, int flags, int buf_index) noexcept {
178 io_uring_prep_recv(sqe, sockfd, buf, len, flags);
179 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
180 sqe->buf_index = buf_index;
181}
182
183inline void prep_sendto(io_uring_sqe *sqe, int sockfd, const void *buf,
184 size_t len, int flags, const struct sockaddr *addr,
185 socklen_t addrlen) noexcept {
186 io_uring_prep_send(sqe, sockfd, buf, len, flags);
187 io_uring_prep_send_set_addr(sqe, addr, addrlen);
188}
189
190inline void prep_sendto_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
191 size_t len, int flags,
192 const struct sockaddr *addr, socklen_t addrlen,
193 int buf_index) noexcept {
194 prep_sendto(sqe, sockfd, buf, len, flags, addr, addrlen);
195 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
196 sqe->buf_index = buf_index;
197}
198
199inline void prep_sendto_zc(io_uring_sqe *sqe, int sockfd, const void *buf,
200 size_t len, int flags, const struct sockaddr *addr,
201 socklen_t addrlen, unsigned zc_flags) noexcept {
202 io_uring_prep_send_zc(sqe, sockfd, buf, len, flags, zc_flags);
203 io_uring_prep_send_set_addr(sqe, addr, addrlen);
204}
205
206inline void prep_sendto_zc_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
207 size_t len, int flags,
208 const struct sockaddr *addr, socklen_t addrlen,
209 unsigned zc_flags, int buf_index) noexcept {
210 prep_sendto_zc(sqe, sockfd, buf, len, flags, addr, addrlen, zc_flags);
211 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
212 sqe->buf_index = buf_index;
213}
214
215#if CONDY_URING_VERSION_GE(2, 15) // >= 2.15
216inline void prep_recv_zc_multishot(io_uring_sqe *sqe, int fd,
217 uint32_t zcrx_id) {
218 io_uring_prep_rw(IORING_OP_RECV_ZC, sqe, fd, nullptr, 0, 0);
219 sqe->ioprio |= IORING_RECV_MULTISHOT;
220 sqe->zcrx_ifq_idx = zcrx_id;
221}
222#endif
223
224inline void prep_read(io_uring_sqe *sqe, int fd, void *buf, unsigned nbytes,
225 __u64 offset, int flags) noexcept {
226 io_uring_prep_read(sqe, fd, buf, nbytes, offset);
227 sqe->rw_flags = flags;
228}
229
230inline void prep_read_fixed(io_uring_sqe *sqe, int fd, void *buf,
231 unsigned nbytes, __u64 offset, int flags,
232 int buf_index) noexcept {
233 io_uring_prep_read_fixed(sqe, fd, buf, nbytes, offset, buf_index);
234 sqe->rw_flags = flags;
235}
236
237inline void prep_write(io_uring_sqe *sqe, int fd, const void *buf,
238 unsigned nbytes, __u64 offset, int flags) noexcept {
239 io_uring_prep_write(sqe, fd, buf, nbytes, offset);
240 sqe->rw_flags = flags;
241}
242
243inline void prep_write_fixed(io_uring_sqe *sqe, int fd, const void *buf,
244 unsigned nbytes, __u64 offset, int flags,
245 int buf_index) noexcept {
246 io_uring_prep_write_fixed(sqe, fd, buf, nbytes, offset, buf_index);
247 sqe->rw_flags = flags;
248}
249
250} // namespace detail
251} // namespace condy
Helper functions for composing asynchronous operations.
Definitions of CQE handlers.
Helper functions for asynchronous operations.
The main namespace for the Condy library.
Definition condy.hpp:37
auto build_zero_copy_op_awaiter(PrepFunc &&func, CQEHandler &&cqe_handler, FreeFunc &&free_func)
Build a zero-copy operation awaiter with custom CQE handler.
auto build_op_awaiter(PrepFunc &&func, CQEHandler &&cqe_handler)
Build a single-shot operation awaiter with custom CQE handler.
auto build_multishot_op_awaiter(PrepFunc &&func, CQEHandler &&cqe_handler, MultiShotFunc &&multishot_func)
Build a multi-shot operation awaiter with custom CQE handler.
auto flag(Sender &&sender)
Decorates an operation with specific io_uring sqe flags.