Condy v1.6.0
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/helpers.hpp"
15
16namespace condy {
17
20
21namespace detail {
22
23class BundledProvidedBufferQueue;
24class BundledProvidedBufferPool;
25
26template <AwaiterLike Awaiter>
27auto maybe_flag_fixed_fd(Awaiter &&op, const FixedFd &) {
28 return flag<IOSQE_FIXED_FILE>(std::forward<Awaiter>(op));
29}
30
31template <AwaiterLike Awaiter> auto maybe_flag_fixed_fd(Awaiter &&op, int) {
32 return std::forward<Awaiter>(op);
33}
34
35template <typename Fd>
36constexpr bool is_fixed_fd_v = std::is_same_v<std::decay_t<Fd>, FixedFd>;
37
38} // namespace detail
39
43template <FdLike Fd1, FdLike Fd2>
44inline auto async_splice(Fd1 fd_in, int64_t off_in, Fd2 fd_out, int64_t off_out,
45 unsigned int nbytes, unsigned int splice_flags) {
46 if constexpr (detail::is_fixed_fd_v<Fd1>) {
47 splice_flags |= SPLICE_F_FD_IN_FIXED;
48 }
49 auto op = detail::make_op_awaiter(io_uring_prep_splice, fd_in, off_in,
50 fd_out, off_out, nbytes, splice_flags);
51 return detail::maybe_flag_fixed_fd(std::move(op), fd_out);
52}
53
57template <FdLike Fd1, FdLike Fd2>
58inline auto async_tee(Fd1 fd_in, Fd2 fd_out, unsigned int nbytes,
59 unsigned int splice_flags) {
60 if constexpr (detail::is_fixed_fd_v<Fd1>) {
61 splice_flags |= SPLICE_F_FD_IN_FIXED;
62 }
63 auto op = detail::make_op_awaiter(io_uring_prep_tee, fd_in, fd_out, nbytes,
64 splice_flags);
65 return detail::maybe_flag_fixed_fd(std::move(op), fd_out);
66}
67
71template <FdLike Fd>
72inline auto async_readv(Fd fd, const struct iovec *iovecs, unsigned nr_vecs,
73 __u64 offset, int flags) {
74 auto op = detail::make_op_awaiter(io_uring_prep_readv2, fd, iovecs, nr_vecs,
75 offset, flags);
76 return detail::maybe_flag_fixed_fd(std::move(op), fd);
77}
78
79#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
83template <FdLike Fd>
84inline auto async_readv(Fd fd, detail::FixedBuffer<const iovec *> iovecs,
85 unsigned nr_vecs, __u64 offset, int flags) {
86 auto op =
87 detail::make_op_awaiter(io_uring_prep_readv_fixed, fd, iovecs.value,
88 nr_vecs, offset, flags, iovecs.buf_index);
89 return detail::maybe_flag_fixed_fd(std::move(op), fd);
90}
91#endif
92
93template <FdLike Fd>
97inline auto async_writev(Fd fd, const struct iovec *iovecs,
98 unsigned int nr_vecs, __u64 offset, int flags) {
99 auto op = detail::make_op_awaiter(io_uring_prep_writev2, fd, iovecs,
100 nr_vecs, offset, flags);
101 return detail::maybe_flag_fixed_fd(std::move(op), fd);
102}
103
104#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
108template <FdLike Fd>
109inline auto async_writev(Fd fd, detail::FixedBuffer<const iovec *> iovecs,
110 unsigned int nr_vecs, __u64 offset, int flags) {
111 auto op =
112 detail::make_op_awaiter(io_uring_prep_writev_fixed, fd, iovecs.value,
113 nr_vecs, offset, flags, iovecs.buf_index);
114 return detail::maybe_flag_fixed_fd(std::move(op), fd);
115}
116#endif
117
121template <FdLike Fd>
122inline auto async_recvmsg(Fd fd, struct msghdr *msg, unsigned flags) {
123 auto op = detail::make_op_awaiter(io_uring_prep_recvmsg, fd, msg, flags);
124 return detail::maybe_flag_fixed_fd(std::move(op), fd);
125}
126
130template <FdLike Fd, typename MultiShotFunc,
131 AnySameAs<ProvidedBufferQueue, ProvidedBufferPool> Buffer>
132inline auto async_recvmsg_multishot(Fd fd, struct msghdr *msg, unsigned flags,
133 Buffer &buf, MultiShotFunc &&func) {
134 auto op = detail::make_multishot_select_buffer_op_awaiter(
135 std::forward<MultiShotFunc>(func), &buf,
136 io_uring_prep_recvmsg_multishot, fd, msg, flags);
137 return detail::maybe_flag_fixed_fd(std::move(op), fd);
138}
139
143template <FdLike Fd>
144inline auto async_sendmsg(Fd fd, const struct msghdr *msg, unsigned flags) {
145 auto op = detail::make_op_awaiter(io_uring_prep_sendmsg, fd, msg, flags);
146 return detail::maybe_flag_fixed_fd(std::move(op), fd);
147}
148
152template <FdLike Fd, typename FreeFunc>
153inline auto async_sendmsg_zc(Fd fd, const struct msghdr *msg, unsigned flags,
154 FreeFunc &&func) {
155 auto op = detail::make_zero_copy_op_awaiter(
156 std::forward<FreeFunc>(func), io_uring_prep_sendmsg_zc, fd, msg, flags);
157 return detail::maybe_flag_fixed_fd(std::move(op), fd);
158}
159
160#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
164template <FdLike Fd, typename FreeFunc>
165inline auto async_sendmsg_zc(Fd fd, detail::FixedBuffer<const msghdr *> msg,
166 unsigned flags, FreeFunc &&func) {
167 auto op = detail::make_zero_copy_op_awaiter(
168 std::forward<FreeFunc>(func), io_uring_prep_sendmsg_zc_fixed, fd,
169 msg.value, flags, msg.buf_index);
170 return detail::maybe_flag_fixed_fd(std::move(op), fd);
171}
172#endif
173
177template <FdLike Fd> inline auto async_fsync(Fd fd, unsigned fsync_flags) {
178 auto op = detail::make_op_awaiter(io_uring_prep_fsync, fd, fsync_flags);
179 return detail::maybe_flag_fixed_fd(std::move(op), fd);
180}
181
185inline auto async_nop() { return detail::make_op_awaiter(io_uring_prep_nop); }
186
187#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
191inline auto async_nop128() {
192 return detail::make_op_awaiter128(io_uring_prep_nop128);
193}
194#endif
195
199inline auto async_timeout(struct __kernel_timespec *ts, unsigned count,
200 unsigned flags) {
201 return detail::make_op_awaiter(io_uring_prep_timeout, ts, count, flags);
202}
203
204#if !IO_URING_CHECK_VERSION(2, 4) // >= 2.4
205
209template <typename MultiShotFunc>
210inline auto async_timeout_multishot(struct __kernel_timespec *ts,
211 unsigned count, unsigned flags,
212 MultiShotFunc &&func) {
213 return detail::make_multishot_op_awaiter(std::forward<MultiShotFunc>(func),
214 io_uring_prep_timeout, ts, count,
215 flags | IORING_TIMEOUT_MULTISHOT);
216}
217#endif
218
222template <FdLike Fd>
223inline auto async_accept(Fd fd, struct sockaddr *addr, socklen_t *addrlen,
224 int flags) {
225 auto op =
226 detail::make_op_awaiter(io_uring_prep_accept, fd, addr, addrlen, flags);
227 return detail::maybe_flag_fixed_fd(std::move(op), fd);
228}
229
233template <FdLike Fd>
234inline auto async_accept_direct(Fd fd, struct sockaddr *addr,
235 socklen_t *addrlen, int flags,
236 unsigned int file_index) {
237 auto op = detail::make_op_awaiter(io_uring_prep_accept_direct, fd, addr,
238 addrlen, flags, file_index);
239 return detail::maybe_flag_fixed_fd(std::move(op), fd);
240}
241
245template <FdLike Fd, typename MultiShotFunc>
246inline auto async_multishot_accept(Fd fd, struct sockaddr *addr,
247 socklen_t *addrlen, int flags,
248 MultiShotFunc &&func) {
249 auto op = detail::make_multishot_op_awaiter(
250 std::forward<MultiShotFunc>(func), io_uring_prep_multishot_accept, fd,
251 addr, addrlen, flags);
252 return detail::maybe_flag_fixed_fd(std::move(op), fd);
253}
254
258template <FdLike Fd, typename MultiShotFunc>
259inline auto async_multishot_accept_direct(Fd fd, struct sockaddr *addr,
260 socklen_t *addrlen, int flags,
261 MultiShotFunc &&func) {
262 auto op = detail::make_multishot_op_awaiter(
263 std::forward<MultiShotFunc>(func),
264 io_uring_prep_multishot_accept_direct, fd, addr, addrlen, flags);
265 return detail::maybe_flag_fixed_fd(std::move(op), fd);
266}
267
271template <FdLike Fd> inline auto async_cancel_fd(Fd fd, unsigned int flags) {
272 if constexpr (detail::is_fixed_fd_v<Fd>) {
273 flags |= IORING_ASYNC_CANCEL_FD_FIXED;
274 }
275 return detail::make_op_awaiter(io_uring_prep_cancel_fd, fd, flags);
276}
277
281inline auto async_link_timeout(struct __kernel_timespec *ts, unsigned flags) {
282 return detail::make_op_awaiter(io_uring_prep_link_timeout, ts, flags);
283}
284
288template <FdLike Fd>
289inline auto async_connect(Fd fd, const struct sockaddr *addr,
290 socklen_t addrlen) {
291 auto op = detail::make_op_awaiter(io_uring_prep_connect, fd, addr, addrlen);
292 return detail::maybe_flag_fixed_fd(std::move(op), fd);
293}
294
298inline auto async_files_update(int *fds, unsigned nr_fds, int offset) {
299 return detail::make_op_awaiter(io_uring_prep_files_update, fds, nr_fds,
300 offset);
301}
302
306template <FdLike Fd>
307inline auto async_fallocate(Fd fd, int mode, __u64 offset, __u64 len) {
308 auto op =
309 detail::make_op_awaiter(io_uring_prep_fallocate, fd, mode, offset, len);
310 return detail::maybe_flag_fixed_fd(std::move(op), fd);
311}
312
316inline auto async_openat(int dfd, const char *path, int flags, mode_t mode) {
317 return detail::make_op_awaiter(io_uring_prep_openat, dfd, path, flags,
318 mode);
319}
320
324inline auto async_openat_direct(int dfd, const char *path, int flags,
325 mode_t mode, unsigned file_index) {
326 return detail::make_op_awaiter(io_uring_prep_openat_direct, dfd, path,
327 flags, mode, file_index);
328}
329
333inline auto async_open(const char *path, int flags, mode_t mode) {
334 return async_openat(AT_FDCWD, path, flags, mode);
335}
336
340inline auto async_open_direct(const char *path, int flags, mode_t mode,
341 unsigned file_index) {
342 return async_openat_direct(AT_FDCWD, path, flags, mode, file_index);
343}
344
348inline auto async_close(int fd) {
349 return detail::make_op_awaiter(io_uring_prep_close, fd);
350}
351
355inline auto async_close(detail::FixedFd fd) {
356 return detail::make_op_awaiter(io_uring_prep_close_direct, fd);
357}
358
362template <FdLike Fd, BufferLike Buffer>
363inline auto async_read(Fd fd, Buffer &&buf, __u64 offset) {
364 auto op = detail::make_op_awaiter(io_uring_prep_read, fd, buf.data(),
365 buf.size(), offset);
366 return detail::maybe_flag_fixed_fd(std::move(op), fd);
367}
368
372template <FdLike Fd, BufferLike Buffer>
373inline auto async_read(Fd fd, detail::FixedBuffer<Buffer> buf, __u64 offset) {
374 auto op =
375 detail::make_op_awaiter(io_uring_prep_read_fixed, fd, buf.value.data(),
376 buf.value.size(), offset, buf.buf_index);
377 return detail::maybe_flag_fixed_fd(std::move(op), fd);
378}
379
383template <FdLike Fd, AnySameAs<ProvidedBufferQueue, ProvidedBufferPool> Buffer>
384inline auto async_read(Fd fd, Buffer &buf, __u64 offset) {
385 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_read,
386 fd, nullptr, 0, offset);
387 return detail::maybe_flag_fixed_fd(std::move(op), fd);
388}
389
390#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
394template <FdLike Fd, AnySameAs<ProvidedBufferQueue, ProvidedBufferPool> Buffer,
395 typename MultiShotFunc>
396inline auto async_read_multishot(Fd fd, Buffer &buf, __u64 offset,
397 MultiShotFunc &&func) {
398 auto op = detail::make_multishot_select_buffer_op_awaiter(
399 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_read_multishot,
400 fd, 0, offset, buf.bgid());
401 return detail::maybe_flag_fixed_fd(std::move(op), fd);
402}
403#endif
404
408template <FdLike Fd, BufferLike Buffer>
409inline auto async_write(Fd fd, Buffer &&buf, __u64 offset) {
410 auto op = detail::make_op_awaiter(io_uring_prep_write, fd, buf.data(),
411 buf.size(), offset);
412 return detail::maybe_flag_fixed_fd(std::move(op), fd);
413}
414
418template <FdLike Fd, BufferLike Buffer>
419inline auto async_write(Fd fd, detail::FixedBuffer<Buffer> buf, __u64 offset) {
420 auto op =
421 detail::make_op_awaiter(io_uring_prep_write_fixed, fd, buf.value.data(),
422 buf.value.size(), offset, buf.buf_index);
423 return detail::maybe_flag_fixed_fd(std::move(op), fd);
424}
425
429inline auto async_statx(int dfd, const char *path, int flags, unsigned mask,
430 struct statx *statxbuf) {
431 return detail::make_op_awaiter(io_uring_prep_statx, dfd, path, flags, mask,
432 statxbuf);
433}
434
438template <FdLike Fd>
439inline auto async_fadvise(Fd fd, __u64 offset, off_t len, int advice) {
440 auto op =
441 detail::make_op_awaiter(io_uring_prep_fadvise, fd, offset, len, advice);
442 return detail::maybe_flag_fixed_fd(std::move(op), fd);
443}
444
445#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
449template <FdLike Fd>
450inline auto async_fadvise64(Fd fd, __u64 offset, off_t len, int advice) {
451 auto op = detail::make_op_awaiter(io_uring_prep_fadvise64, fd, offset, len,
452 advice);
453 return detail::maybe_flag_fixed_fd(std::move(op), fd);
454}
455#endif
456
460inline auto async_madvise(void *addr, __u32 length, int advice) {
461 return detail::make_op_awaiter(io_uring_prep_madvise, addr, length, advice);
462}
463
464#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
468inline auto async_madvise64(void *addr, off_t length, int advice) {
469 auto op =
470 detail::make_op_awaiter(io_uring_prep_madvise64, addr, length, advice);
471 return op;
472}
473#endif
474
475namespace detail {
476
477inline void prep_sendto(io_uring_sqe *sqe, int sockfd, const void *buf,
478 size_t len, int flags, const struct sockaddr *addr,
479 socklen_t addrlen) {
480 io_uring_prep_send(sqe, sockfd, buf, len, flags);
481 io_uring_prep_send_set_addr(sqe, addr, addrlen);
482}
483
484inline void prep_send_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
485 size_t len, int flags, int buf_index) {
486 io_uring_prep_send(sqe, sockfd, buf, len, flags);
487 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
488 sqe->buf_index = buf_index;
489}
490
491inline void prep_sendto_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
492 size_t len, int flags,
493 const struct sockaddr *addr, socklen_t addrlen,
494 int buf_index) {
495 prep_sendto(sqe, sockfd, buf, len, flags, addr, addrlen);
496 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
497 sqe->buf_index = buf_index;
498}
499
500inline void prep_sendto_zc(io_uring_sqe *sqe, int sockfd, const void *buf,
501 size_t len, int flags, const struct sockaddr *addr,
502 socklen_t addrlen, unsigned zc_flags) {
503 io_uring_prep_send_zc(sqe, sockfd, buf, len, flags, zc_flags);
504 io_uring_prep_send_set_addr(sqe, addr, addrlen);
505}
506
507inline void prep_sendto_zc_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
508 size_t len, int flags,
509 const struct sockaddr *addr, socklen_t addrlen,
510 unsigned zc_flags, int buf_index) {
511 prep_sendto_zc(sqe, sockfd, buf, len, flags, addr, addrlen, zc_flags);
512 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
513 sqe->buf_index = buf_index;
514}
515
516} // namespace detail
517
521template <FdLike Fd, BufferLike Buffer>
522inline auto async_send(Fd sockfd, Buffer &&buf, int flags) {
523 auto op = detail::make_op_awaiter(io_uring_prep_send, sockfd, buf.data(),
524 buf.size(), flags);
525 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
526}
527
531template <FdLike Fd>
532inline auto async_send(Fd sockfd, ProvidedBufferQueue &buf, int flags) {
533 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_send,
534 sockfd, nullptr, 0, flags);
535 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
536}
537
538#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
542template <FdLike Fd>
543inline auto async_send(Fd sockfd, detail::BundledProvidedBufferQueue &buf,
544 int flags) {
545 auto op = detail::make_bundle_select_buffer_op_awaiter(
546 &buf, io_uring_prep_send, sockfd, nullptr, 0, flags);
547 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
548}
549#endif
550
554template <FdLike Fd, BufferLike Buffer>
555inline auto async_sendto(Fd sockfd, Buffer &&buf, int flags,
556 const struct sockaddr *addr, socklen_t addrlen) {
557 auto op = detail::make_op_awaiter(detail::prep_sendto, sockfd, buf.data(),
558 buf.size(), flags, addr, addrlen);
559 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
560}
561
565template <FdLike Fd>
566inline auto async_sendto(Fd sockfd, ProvidedBufferQueue &buf, int flags,
567 const struct sockaddr *addr, socklen_t addrlen) {
568 auto op = detail::make_select_buffer_op_awaiter(
569 &buf, detail::prep_sendto, sockfd, nullptr, 0, flags, addr, addrlen);
570 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
571}
572
573#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
577template <FdLike Fd>
578inline auto async_sendto(Fd sockfd, detail::BundledProvidedBufferQueue &buf,
579 int flags, const struct sockaddr *addr,
580 socklen_t addrlen) {
581 auto op = detail::make_bundle_select_buffer_op_awaiter(
582 &buf, detail::prep_sendto, sockfd, nullptr, 0, flags, addr, addrlen);
583 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
584}
585#endif
586
590template <FdLike Fd, typename Buffer, typename FreeFunc>
591inline auto async_send_zc(Fd sockfd, Buffer &&buf, int flags, unsigned zc_flags,
592 FreeFunc &&func) {
593 auto op = detail::make_zero_copy_op_awaiter(
594 std::forward<FreeFunc>(func), io_uring_prep_send_zc, sockfd, buf.data(),
595 buf.size(), flags, zc_flags);
596 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
597}
598
602template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
603inline auto async_send_zc(Fd sockfd, detail::FixedBuffer<Buffer> buf, int flags,
604 unsigned zc_flags, FreeFunc &&func) {
605 auto op = detail::make_zero_copy_op_awaiter(
606 std::forward<FreeFunc>(func), io_uring_prep_send_zc_fixed, sockfd,
607 buf.value.data(), buf.value.size(), flags, zc_flags, buf.buf_index);
608 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
609}
610
614template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
615inline auto async_sendto_zc(Fd sockfd, Buffer &&buf, int flags,
616 const struct sockaddr *addr, socklen_t addrlen,
617 unsigned zc_flags, FreeFunc &&func) {
618 auto op = detail::make_zero_copy_op_awaiter(
619 std::forward<FreeFunc>(func), detail::prep_sendto_zc, sockfd,
620 buf.data(), buf.size(), flags, addr, addrlen, zc_flags);
621 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
622}
623
627template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
628inline auto async_sendto_zc(Fd sockfd, detail::FixedBuffer<Buffer> buf,
629 int flags, const struct sockaddr *addr,
630 socklen_t addrlen, unsigned zc_flags,
631 FreeFunc &&func) {
632 auto op = detail::make_zero_copy_op_awaiter(
633 std::forward<FreeFunc>(func), detail::prep_sendto_zc_fixed, sockfd,
634 buf.value.data(), buf.value.size(), flags, addr, addrlen, zc_flags,
635 buf.buf_index);
636 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
637}
638
642template <FdLike Fd, BufferLike Buffer>
643inline auto async_recv(Fd sockfd, Buffer &&buf, int flags) {
644 auto op = detail::make_op_awaiter(io_uring_prep_recv, sockfd, buf.data(),
645 buf.size(), flags);
646 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
647}
648
652template <FdLike Fd, AnySameAs<ProvidedBufferQueue, ProvidedBufferPool> Buffer>
653inline auto async_recv(Fd sockfd, Buffer &buf, int flags) {
654 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_recv,
655 sockfd, nullptr, 0, flags);
656 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
657}
658
659#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
663template <FdLike Fd, AnySameAs<detail::BundledProvidedBufferQueue,
664 detail::BundledProvidedBufferPool>
665 Buffer>
666inline auto async_recv(Fd sockfd, Buffer &buf, int flags) {
667 auto op = detail::make_bundle_select_buffer_op_awaiter(
668 &buf, io_uring_prep_recv, sockfd, nullptr, 0, flags);
669 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
670}
671#endif
672
676template <FdLike Fd, AnySameAs<ProvidedBufferQueue, ProvidedBufferPool> Buffer,
677 typename MultiShotFunc>
678inline auto async_recv_multishot(Fd sockfd, Buffer &buf, int flags,
679 MultiShotFunc &&func) {
680 auto op = detail::make_multishot_select_buffer_op_awaiter(
681 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_recv_multishot,
682 sockfd, nullptr, 0, flags);
683 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
684}
685
686#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
690template <FdLike Fd,
691 AnySameAs<detail::BundledProvidedBufferQueue,
692 detail::BundledProvidedBufferPool>
693 Buffer,
694 typename MultiShotFunc>
695inline auto async_recv_multishot(Fd sockfd, Buffer &buf, int flags,
696 MultiShotFunc &&func) {
697 auto op = detail::make_multishot_bundle_select_buffer_op_awaiter(
698 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_recv_multishot,
699 sockfd, nullptr, 0, flags);
700 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
701}
702#endif
703
707inline auto async_openat2(int dfd, const char *path, struct open_how *how) {
708 return detail::make_op_awaiter(io_uring_prep_openat2, dfd, path, how);
709}
710
714inline auto async_openat2_direct(int dfd, const char *path,
715 struct open_how *how, unsigned file_index) {
716 return detail::make_op_awaiter(io_uring_prep_openat2_direct, dfd, path, how,
717 file_index);
718}
719
723template <FdLike Fd> inline auto async_shutdown(Fd fd, int how) {
724 auto op = detail::make_op_awaiter(io_uring_prep_shutdown, fd, how);
725 return detail::maybe_flag_fixed_fd(std::move(op), fd);
726}
727
731inline auto async_unlinkat(int dfd, const char *path, int flags) {
732 return detail::make_op_awaiter(io_uring_prep_unlinkat, dfd, path, flags);
733}
734
738inline auto async_unlink(const char *path, int flags) {
739 return async_unlinkat(AT_FDCWD, path, flags);
740}
741
745inline auto async_renameat(int olddfd, const char *oldpath, int newdfd,
746 const char *newpath, unsigned int flags) {
747 return detail::make_op_awaiter(io_uring_prep_renameat, olddfd, oldpath,
748 newdfd, newpath, flags);
749}
750
754inline auto async_rename(const char *oldpath, const char *newpath) {
755 return async_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
756}
757
761template <FdLike Fd>
762inline auto async_sync_file_range(Fd fd, unsigned len, __u64 offset,
763 int flags) {
764 auto op = detail::make_op_awaiter(io_uring_prep_sync_file_range, fd, len,
765 offset, flags);
766 return detail::maybe_flag_fixed_fd(std::move(op), fd);
767}
768
772inline auto async_mkdirat(int dfd, const char *path, mode_t mode) {
773 return detail::make_op_awaiter(io_uring_prep_mkdirat, dfd, path, mode);
774}
775
779inline auto async_mkdir(const char *path, mode_t mode) {
780 return async_mkdirat(AT_FDCWD, path, mode);
781}
782
786inline auto async_symlinkat(const char *target, int newdirfd,
787 const char *linkpath) {
788 return detail::make_op_awaiter(io_uring_prep_symlinkat, target, newdirfd,
789 linkpath);
790}
791
795inline auto async_symlink(const char *target, const char *linkpath) {
796 return async_symlinkat(target, AT_FDCWD, linkpath);
797}
798
802inline auto async_linkat(int olddfd, const char *oldpath, int newdfd,
803 const char *newpath, int flags) {
804 return detail::make_op_awaiter(io_uring_prep_linkat, olddfd, oldpath,
805 newdfd, newpath, flags);
806}
807
811inline auto async_link(const char *oldpath, const char *newpath, int flags) {
812 return async_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, flags);
813}
814
818inline auto async_getxattr(const char *name, char *value, const char *path,
819 unsigned int len) {
820 return detail::make_op_awaiter(io_uring_prep_getxattr, name, value, path,
821 len);
822}
823
827inline auto async_setxattr(const char *name, const char *value,
828 const char *path, int flags, unsigned int len) {
829 return detail::make_op_awaiter(io_uring_prep_setxattr, name, value, path,
830 flags, len);
831}
832
836inline auto async_fgetxattr(int fd, const char *name, char *value,
837 unsigned int len) {
838 return detail::make_op_awaiter(io_uring_prep_fgetxattr, fd, name, value,
839 len);
840}
841
845inline auto async_fsetxattr(int fd, const char *name, const char *value,
846 int flags, unsigned int len) {
847 return detail::make_op_awaiter(io_uring_prep_fsetxattr, fd, name, value,
848 flags, len);
849}
850
854inline auto async_socket(int domain, int type, int protocol,
855 unsigned int flags) {
856 return detail::make_op_awaiter(io_uring_prep_socket, domain, type, protocol,
857 flags);
858}
859
863inline auto async_socket_direct(int domain, int type, int protocol,
864 unsigned file_index, unsigned int flags) {
865 return detail::make_op_awaiter(io_uring_prep_socket_direct, domain, type,
866 protocol, file_index, flags);
867}
868
875template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
876 typename CmdFunc>
877inline auto async_uring_cmd(int cmd_op, Fd fd, CmdFunc &&cmd_func) {
878 auto prep_func = [cmd_op, fd,
879 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
880 auto *sqe = ring->get_sqe();
881 io_uring_prep_uring_cmd(sqe, cmd_op, fd);
882 cmd_func(sqe);
883 return sqe;
884 };
885 auto op = build_op_awaiter<CQEHandler>(std::move(prep_func));
886 return detail::maybe_flag_fixed_fd(std::move(op), fd);
887}
888
892template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
893 typename CmdFunc, typename MultiShotFunc>
894inline auto async_uring_cmd_multishot(int cmd_op, Fd fd, CmdFunc &&cmd_func,
895 MultiShotFunc &&func) {
896 auto prep_func = [cmd_op, fd,
897 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
898 auto *sqe = ring->get_sqe();
899 io_uring_prep_uring_cmd(sqe, cmd_op, fd);
900 cmd_func(sqe);
901 return sqe;
902 };
904 std::move(prep_func), std::forward<MultiShotFunc>(func));
905 return detail::maybe_flag_fixed_fd(std::move(op), fd);
906}
907
908#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
915template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
916 typename CmdFunc>
917inline auto async_uring_cmd128(int cmd_op, Fd fd, CmdFunc &&cmd_func) {
918 auto prep_func = [cmd_op, fd,
919 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
920 auto *sqe = ring->get_sqe128();
921 if (!sqe) {
922 panic_on("SQE128 not enabled in the ring");
923 }
924 io_uring_prep_uring_cmd128(sqe, cmd_op, fd);
925 cmd_func(sqe);
926 return sqe;
927 };
928 auto op = build_op_awaiter<CQEHandler>(std::move(prep_func));
929 return detail::maybe_flag_fixed_fd(std::move(op), fd);
930}
931#endif
932
933#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
937template <FdLike Fd>
938inline auto async_cmd_sock(int cmd_op, Fd fd, int level, int optname,
939 void *optval, int optlen) {
940 auto op = detail::make_op_awaiter(io_uring_prep_cmd_sock, cmd_op, fd, level,
941 optname, optval, optlen);
942 return detail::maybe_flag_fixed_fd(std::move(op), fd);
943}
944#endif
945
946#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
950template <FdLike Fd>
951inline auto async_cmd_getsockname(Fd fd, struct sockaddr *sockaddr,
952 socklen_t *sockaddr_len, int peer) {
953 auto op = detail::make_op_awaiter(io_uring_prep_cmd_getsockname, fd,
954 sockaddr, sockaddr_len, peer);
955 return detail::maybe_flag_fixed_fd(std::move(op), fd);
956}
957#endif
958
959#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
963inline auto async_waitid(idtype_t idtype, id_t id, siginfo_t *infop,
964 int options, unsigned int flags) {
965 return detail::make_op_awaiter(io_uring_prep_waitid, idtype, id, infop,
966 options, flags);
967}
968#endif
969
970#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
974inline auto async_futex_wake(uint32_t *futex, uint64_t val, uint64_t mask,
975 uint32_t futex_flags, unsigned int flags) {
976 return detail::make_op_awaiter(io_uring_prep_futex_wake, futex, val, mask,
977 futex_flags, flags);
978}
979#endif
980
981#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
985inline auto async_futex_wait(uint32_t *futex, uint64_t val, uint64_t mask,
986 uint32_t futex_flags, unsigned int flags) {
987 return detail::make_op_awaiter(io_uring_prep_futex_wait, futex, val, mask,
988 futex_flags, flags);
989}
990#endif
991
992#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
996inline auto async_futex_waitv(struct futex_waitv *futex, uint32_t nr_futex,
997 unsigned int flags) {
998 return detail::make_op_awaiter(io_uring_prep_futex_waitv, futex, nr_futex,
999 flags);
1000}
1001#endif
1002
1003#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
1007inline auto async_fixed_fd_install(int fixed_fd, unsigned int flags) {
1008 return detail::make_op_awaiter(io_uring_prep_fixed_fd_install, fixed_fd,
1009 flags);
1010}
1011#endif
1012
1013#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
1017template <FdLike Fd> inline auto async_ftruncate(Fd fd, loff_t len) {
1018 auto op = detail::make_op_awaiter(io_uring_prep_ftruncate, fd, len);
1019 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1020}
1021#endif
1022
1023#if !IO_URING_CHECK_VERSION(2, 8) // >= 2.8
1027template <FdLike Fd>
1028inline auto async_cmd_discard(Fd fd, uint64_t offset, uint64_t nbytes) {
1029 auto op =
1030 detail::make_op_awaiter(io_uring_prep_cmd_discard, fd, offset, nbytes);
1031 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1032}
1033#endif
1034
1035#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
1039template <FdLike Fd>
1040inline auto async_bind(Fd fd, struct sockaddr *addr, socklen_t addrlen) {
1041 auto op = detail::make_op_awaiter(io_uring_prep_bind, fd, addr, addrlen);
1042 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1043}
1044#endif
1045
1046#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
1050template <FdLike Fd> inline auto async_listen(Fd fd, int backlog) {
1051 auto op = detail::make_op_awaiter(io_uring_prep_listen, fd, backlog);
1052 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1053}
1054#endif
1055
1059inline auto async_epoll_ctl(int epfd, int fd, int op, struct epoll_event *ev) {
1060 return detail::make_op_awaiter(io_uring_prep_epoll_ctl, epfd, fd, op, ev);
1061}
1062
1063#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
1067inline auto async_epoll_wait(int fd, struct epoll_event *events, int maxevents,
1068 unsigned flags) {
1069 return detail::make_op_awaiter(io_uring_prep_epoll_wait, fd, events,
1070 maxevents, flags);
1071}
1072#endif
1073
1074#if !IO_URING_CHECK_VERSION(2, 12) // >= 2.12
1078inline auto async_pipe(int *fds, int pipe_flags) {
1079 return detail::make_op_awaiter(io_uring_prep_pipe, fds, pipe_flags);
1080}
1081#endif
1082
1083#if !IO_URING_CHECK_VERSION(2, 12) // >= 2.12
1087inline auto async_pipe_direct(int *fds, int pipe_flags,
1088 unsigned int file_index) {
1089 return detail::make_op_awaiter(io_uring_prep_pipe_direct, fds, pipe_flags,
1090 file_index);
1091}
1092#endif
1093
1094} // namespace condy
Helper functions for composing asynchronous operations.
Helper functions for asynchronous operations.
The main namespace for the Condy library.
Definition condy.hpp:30
auto async_read_multishot(Fd fd, Buffer &buf, __u64 offset, MultiShotFunc &&func)
See io_uring_prep_read_multishot.
auto async_symlinkat(const char *target, int newdirfd, const char *linkpath)
See io_uring_prep_symlinkat.
auto async_splice(Fd1 fd_in, int64_t off_in, Fd2 fd_out, int64_t off_out, unsigned int nbytes, unsigned int splice_flags)
See io_uring_prep_splice.
auto async_fsetxattr(int fd, const char *name, const char *value, int flags, unsigned int len)
See io_uring_prep_fsetxattr.
auto async_fadvise(Fd fd, __u64 offset, off_t len, int advice)
See io_uring_prep_fadvise.
auto async_writev(Fd fd, const struct iovec *iovecs, unsigned int nr_vecs, __u64 offset, int flags)
See io_uring_prep_writev2.
auto async_fixed_fd_install(int fixed_fd, unsigned int flags)
See io_uring_prep_fixed_fd_install.
auto build_op_awaiter(PrepFunc &&func, Args &&...handler_args)
Build a single-shot operation awaiter with custom CQE handler.
auto async_socket_direct(int domain, int type, int protocol, unsigned file_index, unsigned int flags)
See io_uring_prep_socket_direct.
auto async_madvise64(void *addr, off_t length, int advice)
See io_uring_prep_madvise64.
auto async_fsync(Fd fd, unsigned fsync_flags)
See io_uring_prep_fsync.
auto async_cmd_getsockname(Fd fd, struct sockaddr *sockaddr, socklen_t *sockaddr_len, int peer)
See io_uring_prep_cmd_getsockname.
auto async_ftruncate(Fd fd, loff_t len)
See io_uring_prep_ftruncate.
auto async_recvmsg(Fd fd, struct msghdr *msg, unsigned flags)
See io_uring_prep_recvmsg.
auto async_openat2(int dfd, const char *path, struct open_how *how)
See io_uring_prep_openat2.
auto build_multishot_op_awaiter(PrepFunc &&func, MultiShotFunc &&multishot_func, Args &&...handler_args)
Build a multi-shot operation awaiter with custom CQE handler.
auto async_nop128()
See io_uring_prep_nop128.
auto async_open_direct(const char *path, int flags, mode_t mode, unsigned file_index)
See io_uring_prep_openat_direct.
auto async_write(Fd fd, Buffer &&buf, __u64 offset)
See io_uring_prep_write.
auto async_getxattr(const char *name, char *value, const char *path, unsigned int len)
See io_uring_prep_getxattr.
auto async_unlinkat(int dfd, const char *path, int flags)
See io_uring_prep_unlinkat.
auto async_openat_direct(int dfd, const char *path, int flags, mode_t mode, unsigned file_index)
See io_uring_prep_openat_direct.
auto async_epoll_ctl(int epfd, int fd, int op, struct epoll_event *ev)
See io_uring_prep_epoll_ctl.
auto async_mkdir(const char *path, mode_t mode)
See io_uring_prep_mkdirat.
auto async_fgetxattr(int fd, const char *name, char *value, unsigned int len)
See io_uring_prep_fgetxattr.
auto async_statx(int dfd, const char *path, int flags, unsigned mask, struct statx *statxbuf)
See io_uring_prep_statx.
auto async_sendto_zc(Fd sockfd, Buffer &&buf, int flags, const struct sockaddr *addr, socklen_t addrlen, unsigned zc_flags, FreeFunc &&func)
See io_uring_prep_send_zc and io_uring_prep_send_set_addr.
auto async_cmd_discard(Fd fd, uint64_t offset, uint64_t nbytes)
See io_uring_prep_cmd_discard.
auto async_link(const char *oldpath, const char *newpath, int flags)
See io_uring_prep_linkat.
auto async_multishot_accept_direct(Fd fd, struct sockaddr *addr, socklen_t *addrlen, int flags, MultiShotFunc &&func)
See io_uring_prep_multishot_accept_direct.
auto async_sendto(Fd sockfd, Buffer &&buf, int flags, const struct sockaddr *addr, socklen_t addrlen)
See io_uring_prep_send and io_uring_prep_send_set_addr.
auto async_futex_wake(uint32_t *futex, uint64_t val, uint64_t mask, uint32_t futex_flags, unsigned int flags)
See io_uring_prep_futex_wake.
auto async_recv_multishot(Fd sockfd, Buffer &buf, int flags, MultiShotFunc &&func)
See io_uring_prep_recv_multishot.
auto async_recv(Fd sockfd, Buffer &&buf, int flags)
See io_uring_prep_recv.
auto async_multishot_accept(Fd fd, struct sockaddr *addr, socklen_t *addrlen, int flags, MultiShotFunc &&func)
See io_uring_prep_multishot_accept.
auto async_fallocate(Fd fd, int mode, __u64 offset, __u64 len)
See io_uring_prep_fallocate.
auto async_madvise(void *addr, __u32 length, int advice)
See io_uring_prep_madvise.
auto async_epoll_wait(int fd, struct epoll_event *events, int maxevents, unsigned flags)
See io_uring_prep_epoll_wait.
auto async_symlink(const char *target, const char *linkpath)
See io_uring_prep_symlinkat.
auto async_sync_file_range(Fd fd, unsigned len, __u64 offset, int flags)
See io_uring_prep_sync_file_range.
auto async_fadvise64(Fd fd, __u64 offset, off_t len, int advice)
See io_uring_prep_fadvise64.
auto async_bind(Fd fd, struct sockaddr *addr, socklen_t addrlen)
See io_uring_prep_bind.
auto async_connect(Fd fd, const struct sockaddr *addr, socklen_t addrlen)
See io_uring_prep_connect.
auto async_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options, unsigned int flags)
See io_uring_prep_waitid.
auto async_files_update(int *fds, unsigned nr_fds, int offset)
See io_uring_prep_files_update.
auto async_cmd_sock(int cmd_op, Fd fd, int level, int optname, void *optval, int optlen)
See io_uring_prep_cmd_sock.
auto async_tee(Fd1 fd_in, Fd2 fd_out, unsigned int nbytes, unsigned int splice_flags)
See io_uring_prep_tee.
auto async_recvmsg_multishot(Fd fd, struct msghdr *msg, unsigned flags, Buffer &buf, MultiShotFunc &&func)
See io_uring_prep_recvmsg_multishot.
auto async_futex_wait(uint32_t *futex, uint64_t val, uint64_t mask, uint32_t futex_flags, unsigned int flags)
See io_uring_prep_futex_wait.
auto async_sendmsg(Fd fd, const struct msghdr *msg, unsigned flags)
See io_uring_prep_sendmsg.
auto async_read(Fd fd, Buffer &&buf, __u64 offset)
See io_uring_prep_read.
auto async_cancel_fd(Fd fd, unsigned int flags)
See io_uring_prep_cancel_fd.
auto async_pipe_direct(int *fds, int pipe_flags, unsigned int file_index)
See io_uring_prep_pipe_direct.
auto async_link_timeout(struct __kernel_timespec *ts, unsigned flags)
See io_uring_prep_link_timeout.
auto async_nop()
See io_uring_prep_nop.
auto async_sendmsg_zc(Fd fd, const struct msghdr *msg, unsigned flags, FreeFunc &&func)
See io_uring_prep_sendmsg_zc.
auto async_close(int fd)
See io_uring_prep_close.
auto async_uring_cmd128(int cmd_op, Fd fd, CmdFunc &&cmd_func)
See io_uring_prep_uring_cmd128.
auto async_open(const char *path, int flags, mode_t mode)
See io_uring_prep_openat.
auto flag(Awaiter &&awaiter)
Decorates an awaiter with specific io_uring sqe flags.
auto async_listen(Fd fd, int backlog)
See io_uring_prep_listen.
auto async_send(Fd sockfd, Buffer &&buf, int flags)
See io_uring_prep_send.
auto async_renameat(int olddfd, const char *oldpath, int newdfd, const char *newpath, unsigned int flags)
See io_uring_prep_renameat.
auto async_accept_direct(Fd fd, struct sockaddr *addr, socklen_t *addrlen, int flags, unsigned int file_index)
See io_uring_prep_accept_direct.
auto async_timeout(struct __kernel_timespec *ts, unsigned count, unsigned flags)
See io_uring_prep_timeout.
auto async_rename(const char *oldpath, const char *newpath)
See io_uring_prep_renameat.
auto async_setxattr(const char *name, const char *value, const char *path, int flags, unsigned int len)
See io_uring_prep_setxattr.
auto async_send_zc(Fd sockfd, Buffer &&buf, int flags, unsigned zc_flags, FreeFunc &&func)
See io_uring_prep_send_zc.
auto async_openat2_direct(int dfd, const char *path, struct open_how *how, unsigned file_index)
See io_uring_prep_openat2_direct.
auto async_unlink(const char *path, int flags)
See io_uring_prep_unlinkat.
auto async_accept(Fd fd, struct sockaddr *addr, socklen_t *addrlen, int flags)
See io_uring_prep_accept.
auto async_mkdirat(int dfd, const char *path, mode_t mode)
See io_uring_prep_mkdirat.
auto async_readv(Fd fd, const struct iovec *iovecs, unsigned nr_vecs, __u64 offset, int flags)
See io_uring_prep_readv2.
auto async_openat(int dfd, const char *path, int flags, mode_t mode)
See io_uring_prep_openat.
auto async_timeout_multishot(struct __kernel_timespec *ts, unsigned count, unsigned flags, MultiShotFunc &&func)
See io_uring_prep_timeout.
auto async_linkat(int olddfd, const char *oldpath, int newdfd, const char *newpath, int flags)
See io_uring_prep_linkat.
auto async_uring_cmd(int cmd_op, Fd fd, CmdFunc &&cmd_func)
See io_uring_prep_uring_cmd.
auto async_pipe(int *fds, int pipe_flags)
See io_uring_prep_pipe.
auto async_futex_waitv(struct futex_waitv *futex, uint32_t nr_futex, unsigned int flags)
See io_uring_prep_futex_waitv.
auto async_shutdown(Fd fd, int how)
See io_uring_prep_shutdown.
auto async_socket(int domain, int type, int protocol, unsigned int flags)
See io_uring_prep_socket.
auto async_uring_cmd_multishot(int cmd_op, Fd fd, CmdFunc &&cmd_func, MultiShotFunc &&func)
See io_uring_prep_uring_cmd.