Condy v1.5.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/cqe_handler.hpp"
15#include "condy/helpers.hpp"
17
18namespace condy {
19
20namespace detail {
21
22template <AwaiterLike Awaiter>
23auto maybe_flag_fixed_fd(Awaiter &&op, const FixedFd &) {
24 return flag<IOSQE_FIXED_FILE>(std::forward<Awaiter>(op));
25}
26
27template <AwaiterLike Awaiter> auto maybe_flag_fixed_fd(Awaiter &&op, int) {
28 return std::forward<Awaiter>(op);
29}
30
31template <typename Fd>
32constexpr bool is_fixed_fd_v = std::is_same_v<std::decay_t<Fd>, FixedFd>;
33
34} // namespace detail
35
39template <FdLike Fd1, FdLike Fd2>
40inline auto async_splice(Fd1 fd_in, int64_t off_in, Fd2 fd_out, int64_t off_out,
41 unsigned int nbytes, unsigned int splice_flags) {
42 if constexpr (detail::is_fixed_fd_v<Fd1>) {
43 splice_flags |= SPLICE_F_FD_IN_FIXED;
44 }
45 auto op = detail::make_op_awaiter(io_uring_prep_splice, fd_in, off_in,
46 fd_out, off_out, nbytes, splice_flags);
47 return detail::maybe_flag_fixed_fd(std::move(op), fd_out);
48}
49
53template <FdLike Fd1, FdLike Fd2>
54inline auto async_tee(Fd1 fd_in, Fd2 fd_out, unsigned int nbytes,
55 unsigned int splice_flags) {
56 if constexpr (detail::is_fixed_fd_v<Fd1>) {
57 splice_flags |= SPLICE_F_FD_IN_FIXED;
58 }
59 auto op = detail::make_op_awaiter(io_uring_prep_tee, fd_in, fd_out, nbytes,
60 splice_flags);
61 return detail::maybe_flag_fixed_fd(std::move(op), fd_out);
62}
63
67template <FdLike Fd>
68inline auto async_readv(Fd fd, const struct iovec *iovecs, unsigned nr_vecs,
69 __u64 offset, int flags) {
70 auto op = detail::make_op_awaiter(io_uring_prep_readv2, fd, iovecs, nr_vecs,
71 offset, flags);
72 return detail::maybe_flag_fixed_fd(std::move(op), fd);
73}
74
75#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
79template <FdLike Fd>
80inline auto async_readv(Fd fd, detail::FixedBuffer<const iovec *> iovecs,
81 unsigned nr_vecs, __u64 offset, int flags) {
82 auto op =
83 detail::make_op_awaiter(io_uring_prep_readv_fixed, fd, iovecs.value,
84 nr_vecs, offset, flags, iovecs.buf_index);
85 return detail::maybe_flag_fixed_fd(std::move(op), fd);
86}
87#endif
88
89template <FdLike Fd>
93inline auto async_writev(Fd fd, const struct iovec *iovecs,
94 unsigned int nr_vecs, __u64 offset, int flags) {
95 auto op = detail::make_op_awaiter(io_uring_prep_writev2, fd, iovecs,
96 nr_vecs, offset, flags);
97 return detail::maybe_flag_fixed_fd(std::move(op), fd);
98}
99
100#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
104template <FdLike Fd>
105inline auto async_writev(Fd fd, detail::FixedBuffer<const iovec *> iovecs,
106 unsigned int nr_vecs, __u64 offset, int flags) {
107 auto op =
108 detail::make_op_awaiter(io_uring_prep_writev_fixed, fd, iovecs.value,
109 nr_vecs, offset, flags, iovecs.buf_index);
110 return detail::maybe_flag_fixed_fd(std::move(op), fd);
111}
112#endif
113
117template <FdLike Fd>
118inline auto async_recvmsg(Fd fd, struct msghdr *msg, unsigned flags) {
119 auto op = detail::make_op_awaiter(io_uring_prep_recvmsg, fd, msg, flags);
120 return detail::maybe_flag_fixed_fd(std::move(op), fd);
121}
122
126template <FdLike Fd, typename MultiShotFunc, NotBundledBufferRing Buffer>
127inline auto async_recvmsg_multishot(Fd fd, struct msghdr *msg, unsigned flags,
128 Buffer &buf, MultiShotFunc &&func) {
129 auto op = detail::make_multishot_select_buffer_op_awaiter(
130 std::forward<MultiShotFunc>(func), &buf,
131 io_uring_prep_recvmsg_multishot, fd, msg, flags);
132 return detail::maybe_flag_fixed_fd(std::move(op), fd);
133}
134
138template <FdLike Fd>
139inline auto async_sendmsg(Fd fd, const struct msghdr *msg, unsigned flags) {
140 auto op = detail::make_op_awaiter(io_uring_prep_sendmsg, fd, msg, flags);
141 return detail::maybe_flag_fixed_fd(std::move(op), fd);
142}
143
147template <FdLike Fd, typename FreeFunc>
148inline auto async_sendmsg_zc(Fd fd, const struct msghdr *msg, unsigned flags,
149 FreeFunc &&func) {
150 auto op = detail::make_zero_copy_op_awaiter(
151 std::forward<FreeFunc>(func), io_uring_prep_sendmsg_zc, fd, msg, flags);
152 return detail::maybe_flag_fixed_fd(std::move(op), fd);
153}
154
155#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
159template <FdLike Fd, typename FreeFunc>
160inline auto async_sendmsg_zc(Fd fd, detail::FixedBuffer<const msghdr *> msg,
161 unsigned flags, FreeFunc &&func) {
162 auto op = detail::make_zero_copy_op_awaiter(
163 std::forward<FreeFunc>(func), io_uring_prep_sendmsg_zc_fixed, fd,
164 msg.value, flags, msg.buf_index);
165 return detail::maybe_flag_fixed_fd(std::move(op), fd);
166}
167#endif
168
172template <FdLike Fd> inline auto async_fsync(Fd fd, unsigned fsync_flags) {
173 auto op = detail::make_op_awaiter(io_uring_prep_fsync, fd, fsync_flags);
174 return detail::maybe_flag_fixed_fd(std::move(op), fd);
175}
176
180inline auto async_nop() { return detail::make_op_awaiter(io_uring_prep_nop); }
181
182#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
186inline auto async_nop128() {
187 return detail::make_op_awaiter128(io_uring_prep_nop128);
188}
189#endif
190
194inline auto async_timeout(struct __kernel_timespec *ts, unsigned count,
195 unsigned flags) {
196 return detail::make_op_awaiter(io_uring_prep_timeout, ts, count, flags);
197}
198
199#if !IO_URING_CHECK_VERSION(2, 4) // >= 2.4
200
204template <typename MultiShotFunc>
205inline auto async_timeout_multishot(struct __kernel_timespec *ts,
206 unsigned count, unsigned flags,
207 MultiShotFunc &&func) {
208 return detail::make_multishot_op_awaiter(std::forward<MultiShotFunc>(func),
209 io_uring_prep_timeout, ts, count,
210 flags | IORING_TIMEOUT_MULTISHOT);
211}
212#endif
213
217template <FdLike Fd>
218inline auto async_accept(Fd fd, struct sockaddr *addr, socklen_t *addrlen,
219 int flags) {
220 auto op =
221 detail::make_op_awaiter(io_uring_prep_accept, fd, addr, addrlen, flags);
222 return detail::maybe_flag_fixed_fd(std::move(op), fd);
223}
224
228template <FdLike Fd>
229inline auto async_accept_direct(Fd fd, struct sockaddr *addr,
230 socklen_t *addrlen, int flags,
231 unsigned int file_index) {
232 auto op = detail::make_op_awaiter(io_uring_prep_accept_direct, fd, addr,
233 addrlen, flags, file_index);
234 return detail::maybe_flag_fixed_fd(std::move(op), fd);
235}
236
240template <FdLike Fd, typename MultiShotFunc>
241inline auto async_multishot_accept(Fd fd, struct sockaddr *addr,
242 socklen_t *addrlen, int flags,
243 MultiShotFunc &&func) {
244 auto op = detail::make_multishot_op_awaiter(
245 std::forward<MultiShotFunc>(func), io_uring_prep_multishot_accept, fd,
246 addr, addrlen, flags);
247 return detail::maybe_flag_fixed_fd(std::move(op), fd);
248}
249
253template <FdLike Fd, typename MultiShotFunc>
254inline auto async_multishot_accept_direct(Fd fd, struct sockaddr *addr,
255 socklen_t *addrlen, int flags,
256 MultiShotFunc &&func) {
257 auto op = detail::make_multishot_op_awaiter(
258 std::forward<MultiShotFunc>(func),
259 io_uring_prep_multishot_accept_direct, fd, addr, addrlen, flags);
260 return detail::maybe_flag_fixed_fd(std::move(op), fd);
261}
262
266template <FdLike Fd> inline auto async_cancel_fd(Fd fd, unsigned int flags) {
267 if constexpr (detail::is_fixed_fd_v<Fd>) {
268 flags |= IORING_ASYNC_CANCEL_FD_FIXED;
269 }
270 return detail::make_op_awaiter(io_uring_prep_cancel_fd, fd, flags);
271}
272
276inline auto async_link_timeout(struct __kernel_timespec *ts, unsigned flags) {
277 return detail::make_op_awaiter(io_uring_prep_link_timeout, ts, flags);
278}
279
283template <FdLike Fd>
284inline auto async_connect(Fd fd, const struct sockaddr *addr,
285 socklen_t addrlen) {
286 auto op = detail::make_op_awaiter(io_uring_prep_connect, fd, addr, addrlen);
287 return detail::maybe_flag_fixed_fd(std::move(op), fd);
288}
289
293inline auto async_files_update(int *fds, unsigned nr_fds, int offset) {
294 return detail::make_op_awaiter(io_uring_prep_files_update, fds, nr_fds,
295 offset);
296}
297
301template <FdLike Fd>
302inline auto async_fallocate(Fd fd, int mode, __u64 offset, __u64 len) {
303 auto op =
304 detail::make_op_awaiter(io_uring_prep_fallocate, fd, mode, offset, len);
305 return detail::maybe_flag_fixed_fd(std::move(op), fd);
306}
307
311inline auto async_openat(int dfd, const char *path, int flags, mode_t mode) {
312 return detail::make_op_awaiter(io_uring_prep_openat, dfd, path, flags,
313 mode);
314}
315
319inline auto async_openat_direct(int dfd, const char *path, int flags,
320 mode_t mode, unsigned file_index) {
321 return detail::make_op_awaiter(io_uring_prep_openat_direct, dfd, path,
322 flags, mode, file_index);
323}
324
328inline auto async_open(const char *path, int flags, mode_t mode) {
329 return async_openat(AT_FDCWD, path, flags, mode);
330}
331
335inline auto async_open_direct(const char *path, int flags, mode_t mode,
336 unsigned file_index) {
337 return async_openat_direct(AT_FDCWD, path, flags, mode, file_index);
338}
339
343inline auto async_close(int fd) {
344 return detail::make_op_awaiter(io_uring_prep_close, fd);
345}
346
350inline auto async_close(detail::FixedFd fd) {
351 return detail::make_op_awaiter(io_uring_prep_close_direct, fd);
352}
353
357template <FdLike Fd, BufferLike Buffer>
358inline auto async_read(Fd fd, Buffer &&buf, __u64 offset) {
359 auto op = detail::make_op_awaiter(io_uring_prep_read, fd, buf.data(),
360 buf.size(), offset);
361 return detail::maybe_flag_fixed_fd(std::move(op), fd);
362}
363
367template <FdLike Fd, BufferLike Buffer>
368inline auto async_read(Fd fd, detail::FixedBuffer<Buffer> buf, __u64 offset) {
369 auto op =
370 detail::make_op_awaiter(io_uring_prep_read_fixed, fd, buf.value.data(),
371 buf.value.size(), offset, buf.buf_index);
372 return detail::maybe_flag_fixed_fd(std::move(op), fd);
373}
374
378template <FdLike Fd, NotBundledBufferRing Buffer>
379inline auto async_read(Fd fd, Buffer &buf, __u64 offset) {
380 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_read,
381 fd, nullptr, 0, offset);
382 return detail::maybe_flag_fixed_fd(std::move(op), fd);
383}
384
385#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
389template <FdLike Fd, NotBundledBufferRing Buffer, typename MultiShotFunc>
390inline auto async_read_multishot(Fd fd, Buffer &buf, __u64 offset,
391 MultiShotFunc &&func) {
392 auto op = detail::make_multishot_select_buffer_op_awaiter(
393 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_read_multishot,
394 fd, 0, offset, buf.bgid());
395 return detail::maybe_flag_fixed_fd(std::move(op), fd);
396}
397#endif
398
402template <FdLike Fd, BufferLike Buffer>
403inline auto async_write(Fd fd, Buffer &&buf, __u64 offset) {
404 auto op = detail::make_op_awaiter(io_uring_prep_write, fd, buf.data(),
405 buf.size(), offset);
406 return detail::maybe_flag_fixed_fd(std::move(op), fd);
407}
408
412template <FdLike Fd, BufferLike Buffer>
413inline auto async_write(Fd fd, detail::FixedBuffer<Buffer> buf, __u64 offset) {
414 auto op =
415 detail::make_op_awaiter(io_uring_prep_write_fixed, fd, buf.value.data(),
416 buf.value.size(), offset, buf.buf_index);
417 return detail::maybe_flag_fixed_fd(std::move(op), fd);
418}
419
423inline auto async_statx(int dfd, const char *path, int flags, unsigned mask,
424 struct statx *statxbuf) {
425 return detail::make_op_awaiter(io_uring_prep_statx, dfd, path, flags, mask,
426 statxbuf);
427}
428
432template <FdLike Fd>
433inline auto async_fadvise(Fd fd, __u64 offset, off_t len, int advice) {
434 auto op =
435 detail::make_op_awaiter(io_uring_prep_fadvise, fd, offset, len, advice);
436 return detail::maybe_flag_fixed_fd(std::move(op), fd);
437}
438
439#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
443template <FdLike Fd>
444inline auto async_fadvise64(Fd fd, __u64 offset, off_t len, int advice) {
445 auto op = detail::make_op_awaiter(io_uring_prep_fadvise64, fd, offset, len,
446 advice);
447 return detail::maybe_flag_fixed_fd(std::move(op), fd);
448}
449#endif
450
454inline auto async_madvise(void *addr, __u32 length, int advice) {
455 return detail::make_op_awaiter(io_uring_prep_madvise, addr, length, advice);
456}
457
458#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
462inline auto async_madvise64(void *addr, off_t length, int advice) {
463 auto op =
464 detail::make_op_awaiter(io_uring_prep_madvise64, addr, length, advice);
465 return op;
466}
467#endif
468
469namespace detail {
470
471inline void prep_sendto(io_uring_sqe *sqe, int sockfd, const void *buf,
472 size_t len, int flags, const struct sockaddr *addr,
473 socklen_t addrlen) {
474 io_uring_prep_send(sqe, sockfd, buf, len, flags);
475 io_uring_prep_send_set_addr(sqe, addr, addrlen);
476}
477
478inline void prep_send_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
479 size_t len, int flags, int buf_index) {
480 io_uring_prep_send(sqe, sockfd, buf, len, flags);
481 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
482 sqe->buf_index = buf_index;
483}
484
485inline void prep_sendto_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
486 size_t len, int flags,
487 const struct sockaddr *addr, socklen_t addrlen,
488 int buf_index) {
489 prep_sendto(sqe, sockfd, buf, len, flags, addr, addrlen);
490 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
491 sqe->buf_index = buf_index;
492}
493
494inline void prep_sendto_zc(io_uring_sqe *sqe, int sockfd, const void *buf,
495 size_t len, int flags, const struct sockaddr *addr,
496 socklen_t addrlen, unsigned zc_flags) {
497 io_uring_prep_send_zc(sqe, sockfd, buf, len, flags, zc_flags);
498 io_uring_prep_send_set_addr(sqe, addr, addrlen);
499}
500
501inline void prep_sendto_zc_fixed(io_uring_sqe *sqe, int sockfd, const void *buf,
502 size_t len, int flags,
503 const struct sockaddr *addr, socklen_t addrlen,
504 unsigned zc_flags, int buf_index) {
505 prep_sendto_zc(sqe, sockfd, buf, len, flags, addr, addrlen, zc_flags);
506 sqe->ioprio |= IORING_RECVSEND_FIXED_BUF;
507 sqe->buf_index = buf_index;
508}
509
510} // namespace detail
511
515template <FdLike Fd, BufferLike Buffer>
516inline auto async_send(Fd sockfd, Buffer &&buf, int flags) {
517 auto op = detail::make_op_awaiter(io_uring_prep_send, sockfd, buf.data(),
518 buf.size(), flags);
519 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
520}
521
525template <FdLike Fd>
526inline auto async_send(Fd sockfd, ProvidedBufferQueue &buf, int flags) {
527 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_send,
528 sockfd, nullptr, 0, flags);
529 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
530}
531
532#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
536template <FdLike Fd>
537inline auto async_send(Fd sockfd, detail::BundledProvidedBufferQueue &buf,
538 int flags) {
539 auto op = detail::make_bundle_select_buffer_op_awaiter(
540 &buf, io_uring_prep_send, sockfd, nullptr, 0, flags);
541 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
542}
543#endif
544
548template <FdLike Fd, BufferLike Buffer>
549inline auto async_sendto(Fd sockfd, Buffer &&buf, int flags,
550 const struct sockaddr *addr, socklen_t addrlen) {
551 auto op = detail::make_op_awaiter(detail::prep_sendto, sockfd, buf.data(),
552 buf.size(), flags, addr, addrlen);
553 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
554}
555
559template <FdLike Fd>
560inline auto async_sendto(Fd sockfd, ProvidedBufferQueue &buf, int flags,
561 const struct sockaddr *addr, socklen_t addrlen) {
562 auto op = detail::make_select_buffer_op_awaiter(
563 &buf, detail::prep_sendto, sockfd, nullptr, 0, flags, addr, addrlen);
564 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
565}
566
567#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
571template <FdLike Fd>
572inline auto async_sendto(Fd sockfd, detail::BundledProvidedBufferQueue &buf,
573 int flags, const struct sockaddr *addr,
574 socklen_t addrlen) {
575 auto op = detail::make_bundle_select_buffer_op_awaiter(
576 &buf, detail::prep_sendto, sockfd, nullptr, 0, flags, addr, addrlen);
577 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
578}
579#endif
580
584template <FdLike Fd, typename Buffer, typename FreeFunc>
585inline auto async_send_zc(Fd sockfd, Buffer &&buf, int flags, unsigned zc_flags,
586 FreeFunc &&func) {
587 auto op = detail::make_zero_copy_op_awaiter(
588 std::forward<FreeFunc>(func), io_uring_prep_send_zc, sockfd, buf.data(),
589 buf.size(), flags, zc_flags);
590 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
591}
592
596template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
597inline auto async_send_zc(Fd sockfd, detail::FixedBuffer<Buffer> buf, int flags,
598 unsigned zc_flags, FreeFunc &&func) {
599 auto op = detail::make_zero_copy_op_awaiter(
600 std::forward<FreeFunc>(func), io_uring_prep_send_zc_fixed, sockfd,
601 buf.value.data(), buf.value.size(), flags, zc_flags, buf.buf_index);
602 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
603}
604
608template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
609inline auto async_sendto_zc(Fd sockfd, Buffer &&buf, int flags,
610 const struct sockaddr *addr, socklen_t addrlen,
611 unsigned zc_flags, FreeFunc &&func) {
612 auto op = detail::make_zero_copy_op_awaiter(
613 std::forward<FreeFunc>(func), detail::prep_sendto_zc, sockfd,
614 buf.data(), buf.size(), flags, addr, addrlen, zc_flags);
615 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
616}
617
621template <FdLike Fd, BufferLike Buffer, typename FreeFunc>
622inline auto async_sendto_zc(Fd sockfd, detail::FixedBuffer<Buffer> buf,
623 int flags, const struct sockaddr *addr,
624 socklen_t addrlen, unsigned zc_flags,
625 FreeFunc &&func) {
626 auto op = detail::make_zero_copy_op_awaiter(
627 std::forward<FreeFunc>(func), detail::prep_sendto_zc_fixed, sockfd,
628 buf.value.data(), buf.value.size(), flags, addr, addrlen, zc_flags,
629 buf.buf_index);
630 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
631}
632
636template <FdLike Fd, BufferLike Buffer>
637inline auto async_recv(Fd sockfd, Buffer &&buf, int flags) {
638 auto op = detail::make_op_awaiter(io_uring_prep_recv, sockfd, buf.data(),
639 buf.size(), flags);
640 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
641}
642
646template <FdLike Fd, NotBundledBufferRing Buffer>
647inline auto async_recv(Fd sockfd, Buffer &buf, int flags) {
648 auto op = detail::make_select_buffer_op_awaiter(&buf, io_uring_prep_recv,
649 sockfd, nullptr, 0, flags);
650 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
651}
652
653#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
657template <FdLike Fd, BundledBufferRing Buffer>
658inline auto async_recv(Fd sockfd, Buffer &buf, int flags) {
659 auto op = detail::make_bundle_select_buffer_op_awaiter(
660 &buf, io_uring_prep_recv, sockfd, nullptr, 0, flags);
661 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
662}
663#endif
664
668template <FdLike Fd, NotBundledBufferRing Buffer, typename MultiShotFunc>
669inline auto async_recv_multishot(Fd sockfd, Buffer &buf, int flags,
670 MultiShotFunc &&func) {
671 auto op = detail::make_multishot_select_buffer_op_awaiter(
672 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_recv_multishot,
673 sockfd, nullptr, 0, flags);
674 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
675}
676
677#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
681template <FdLike Fd, BundledBufferRing Buffer, typename MultiShotFunc>
682inline auto async_recv_multishot(Fd sockfd, Buffer &buf, int flags,
683 MultiShotFunc &&func) {
684 auto op = detail::make_multishot_bundle_select_buffer_op_awaiter(
685 std::forward<MultiShotFunc>(func), &buf, io_uring_prep_recv_multishot,
686 sockfd, nullptr, 0, flags);
687 return detail::maybe_flag_fixed_fd(std::move(op), sockfd);
688}
689#endif
690
694inline auto async_openat2(int dfd, const char *path, struct open_how *how) {
695 return detail::make_op_awaiter(io_uring_prep_openat2, dfd, path, how);
696}
697
701inline auto async_openat2_direct(int dfd, const char *path,
702 struct open_how *how, unsigned file_index) {
703 return detail::make_op_awaiter(io_uring_prep_openat2_direct, dfd, path, how,
704 file_index);
705}
706
710template <FdLike Fd> inline auto async_shutdown(Fd fd, int how) {
711 auto op = detail::make_op_awaiter(io_uring_prep_shutdown, fd, how);
712 return detail::maybe_flag_fixed_fd(std::move(op), fd);
713}
714
718inline auto async_unlinkat(int dfd, const char *path, int flags) {
719 return detail::make_op_awaiter(io_uring_prep_unlinkat, dfd, path, flags);
720}
721
725inline auto async_unlink(const char *path, int flags) {
726 return async_unlinkat(AT_FDCWD, path, flags);
727}
728
732inline auto async_renameat(int olddfd, const char *oldpath, int newdfd,
733 const char *newpath, unsigned int flags) {
734 return detail::make_op_awaiter(io_uring_prep_renameat, olddfd, oldpath,
735 newdfd, newpath, flags);
736}
737
741inline auto async_rename(const char *oldpath, const char *newpath) {
742 return async_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
743}
744
748template <FdLike Fd>
749inline auto async_sync_file_range(Fd fd, unsigned len, __u64 offset,
750 int flags) {
751 auto op = detail::make_op_awaiter(io_uring_prep_sync_file_range, fd, len,
752 offset, flags);
753 return detail::maybe_flag_fixed_fd(std::move(op), fd);
754}
755
759inline auto async_mkdirat(int dfd, const char *path, mode_t mode) {
760 return detail::make_op_awaiter(io_uring_prep_mkdirat, dfd, path, mode);
761}
762
766inline auto async_mkdir(const char *path, mode_t mode) {
767 return async_mkdirat(AT_FDCWD, path, mode);
768}
769
773inline auto async_symlinkat(const char *target, int newdirfd,
774 const char *linkpath) {
775 return detail::make_op_awaiter(io_uring_prep_symlinkat, target, newdirfd,
776 linkpath);
777}
778
782inline auto async_symlink(const char *target, const char *linkpath) {
783 return async_symlinkat(target, AT_FDCWD, linkpath);
784}
785
789inline auto async_linkat(int olddfd, const char *oldpath, int newdfd,
790 const char *newpath, int flags) {
791 return detail::make_op_awaiter(io_uring_prep_linkat, olddfd, oldpath,
792 newdfd, newpath, flags);
793}
794
798inline auto async_link(const char *oldpath, const char *newpath, int flags) {
799 return async_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, flags);
800}
801
805inline auto async_getxattr(const char *name, char *value, const char *path,
806 unsigned int len) {
807 return detail::make_op_awaiter(io_uring_prep_getxattr, name, value, path,
808 len);
809}
810
814inline auto async_setxattr(const char *name, const char *value,
815 const char *path, int flags, unsigned int len) {
816 return detail::make_op_awaiter(io_uring_prep_setxattr, name, value, path,
817 flags, len);
818}
819
823inline auto async_fgetxattr(int fd, const char *name, char *value,
824 unsigned int len) {
825 return detail::make_op_awaiter(io_uring_prep_fgetxattr, fd, name, value,
826 len);
827}
828
832inline auto async_fsetxattr(int fd, const char *name, const char *value,
833 int flags, unsigned int len) {
834 return detail::make_op_awaiter(io_uring_prep_fsetxattr, fd, name, value,
835 flags, len);
836}
837
841inline auto async_socket(int domain, int type, int protocol,
842 unsigned int flags) {
843 return detail::make_op_awaiter(io_uring_prep_socket, domain, type, protocol,
844 flags);
845}
846
850inline auto async_socket_direct(int domain, int type, int protocol,
851 unsigned file_index, unsigned int flags) {
852 return detail::make_op_awaiter(io_uring_prep_socket_direct, domain, type,
853 protocol, file_index, flags);
854}
855
862template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
863 typename CmdFunc>
864inline auto async_uring_cmd(int cmd_op, Fd fd, CmdFunc &&cmd_func) {
865 auto prep_func = [cmd_op, fd,
866 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
867 auto *sqe = ring->get_sqe();
868 io_uring_prep_uring_cmd(sqe, cmd_op, fd);
869 cmd_func(sqe);
870 return sqe;
871 };
872 auto op = build_op_awaiter<CQEHandler>(std::move(prep_func));
873 return detail::maybe_flag_fixed_fd(std::move(op), fd);
874}
875
879template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
880 typename CmdFunc, typename MultiShotFunc>
881inline auto async_uring_cmd_multishot(int cmd_op, Fd fd, CmdFunc &&cmd_func,
882 MultiShotFunc &&func) {
883 auto prep_func = [cmd_op, fd,
884 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
885 auto *sqe = ring->get_sqe();
886 io_uring_prep_uring_cmd(sqe, cmd_op, fd);
887 cmd_func(sqe);
888 return sqe;
889 };
891 std::move(prep_func), std::forward<MultiShotFunc>(func));
892 return detail::maybe_flag_fixed_fd(std::move(op), fd);
893}
894
895#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
902template <CQEHandlerLike CQEHandler = SimpleCQEHandler, FdLike Fd,
903 typename CmdFunc>
904inline auto async_uring_cmd128(int cmd_op, Fd fd, CmdFunc &&cmd_func) {
905 auto prep_func = [cmd_op, fd,
906 cmd_func = std::forward<CmdFunc>(cmd_func)](Ring *ring) {
907 auto *sqe = ring->get_sqe128();
908 io_uring_prep_uring_cmd128(sqe, cmd_op, fd);
909 cmd_func(sqe);
910 return sqe;
911 };
912 auto op = build_op_awaiter<CQEHandler>(std::move(prep_func));
913 return detail::maybe_flag_fixed_fd(std::move(op), fd);
914}
915#endif
916
917#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
921template <FdLike Fd>
922inline auto async_cmd_sock(int cmd_op, Fd fd, int level, int optname,
923 void *optval, int optlen) {
924 auto op = detail::make_op_awaiter(io_uring_prep_cmd_sock, cmd_op, fd, level,
925 optname, optval, optlen);
926 return detail::maybe_flag_fixed_fd(std::move(op), fd);
927}
928#endif
929
930#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
934template <FdLike Fd>
935inline auto async_cmd_getsockname(Fd fd, struct sockaddr *sockaddr,
936 socklen_t *sockaddr_len, int peer) {
937 auto op = detail::make_op_awaiter(io_uring_prep_cmd_getsockname, fd,
938 sockaddr, sockaddr_len, peer);
939 return detail::maybe_flag_fixed_fd(std::move(op), fd);
940}
941#endif
942
943#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
947inline auto async_waitid(idtype_t idtype, id_t id, siginfo_t *infop,
948 int options, unsigned int flags) {
949 return detail::make_op_awaiter(io_uring_prep_waitid, idtype, id, infop,
950 options, flags);
951}
952#endif
953
954#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
958inline auto async_futex_wake(uint32_t *futex, uint64_t val, uint64_t mask,
959 uint32_t futex_flags, unsigned int flags) {
960 return detail::make_op_awaiter(io_uring_prep_futex_wake, futex, val, mask,
961 futex_flags, flags);
962}
963#endif
964
965#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
969inline auto async_futex_wait(uint32_t *futex, uint64_t val, uint64_t mask,
970 uint32_t futex_flags, unsigned int flags) {
971 return detail::make_op_awaiter(io_uring_prep_futex_wait, futex, val, mask,
972 futex_flags, flags);
973}
974#endif
975
976#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
980inline auto async_futex_waitv(struct futex_waitv *futex, uint32_t nr_futex,
981 unsigned int flags) {
982 return detail::make_op_awaiter(io_uring_prep_futex_waitv, futex, nr_futex,
983 flags);
984}
985#endif
986
987#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
991inline auto async_fixed_fd_install(int fixed_fd, unsigned int flags) {
992 return detail::make_op_awaiter(io_uring_prep_fixed_fd_install, fixed_fd,
993 flags);
994}
995#endif
996
997#if !IO_URING_CHECK_VERSION(2, 4) // >= 2.4
1003[[deprecated("async_fixed_fd_send is deprecated and will be removed in a "
1004 "future version")]]
1005inline auto async_fixed_fd_send(FdTable &dst, int source_fd, int target_fd,
1006 unsigned int flags) {
1007 void *payload = nullptr;
1008 if (static_cast<unsigned int>(target_fd) != CONDY_FILE_INDEX_ALLOC) {
1009 // NOLINTNEXTLINE(performance-no-int-to-ptr)
1010 payload = reinterpret_cast<void *>((target_fd + 1) << 3);
1011 }
1012 return detail::make_op_awaiter(
1013 io_uring_prep_msg_ring_fd, dst.ring_.ring_fd, source_fd, target_fd,
1014 reinterpret_cast<uint64_t>(encode_work(payload, WorkType::SendFd)),
1015 flags);
1016}
1017#endif
1018
1019#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
1023template <FdLike Fd> inline auto async_ftruncate(Fd fd, loff_t len) {
1024 auto op = detail::make_op_awaiter(io_uring_prep_ftruncate, fd, len);
1025 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1026}
1027#endif
1028
1029#if !IO_URING_CHECK_VERSION(2, 8) // >= 2.8
1033template <FdLike Fd>
1034inline auto async_cmd_discard(Fd fd, uint64_t offset, uint64_t nbytes) {
1035 auto op =
1036 detail::make_op_awaiter(io_uring_prep_cmd_discard, fd, offset, nbytes);
1037 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1038}
1039#endif
1040
1041#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
1045template <FdLike Fd>
1046inline auto async_bind(Fd fd, struct sockaddr *addr, socklen_t addrlen) {
1047 auto op = detail::make_op_awaiter(io_uring_prep_bind, fd, addr, addrlen);
1048 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1049}
1050#endif
1051
1052#if !IO_URING_CHECK_VERSION(2, 7) // >= 2.7
1056template <FdLike Fd> inline auto async_listen(Fd fd, int backlog) {
1057 auto op = detail::make_op_awaiter(io_uring_prep_listen, fd, backlog);
1058 return detail::maybe_flag_fixed_fd(std::move(op), fd);
1059}
1060#endif
1061
1065inline auto async_epoll_ctl(int epfd, int fd, int op, struct epoll_event *ev) {
1066 return detail::make_op_awaiter(io_uring_prep_epoll_ctl, epfd, fd, op, ev);
1067}
1068
1069#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
1073inline auto async_epoll_wait(int fd, struct epoll_event *events, int maxevents,
1074 unsigned flags) {
1075 return detail::make_op_awaiter(io_uring_prep_epoll_wait, fd, events,
1076 maxevents, flags);
1077}
1078#endif
1079
1080#if !IO_URING_CHECK_VERSION(2, 12) // >= 2.12
1084inline auto async_pipe(int *fds, int pipe_flags) {
1085 return detail::make_op_awaiter(io_uring_prep_pipe, fds, pipe_flags);
1086}
1087#endif
1088
1089#if !IO_URING_CHECK_VERSION(2, 12) // >= 2.12
1093inline auto async_pipe_direct(int *fds, int pipe_flags,
1094 unsigned int file_index) {
1095 return detail::make_op_awaiter(io_uring_prep_pipe_direct, fds, pipe_flags,
1096 file_index);
1097}
1098#endif
1099
1100} // namespace condy
Helper functions for composing asynchronous operations.
Definitions of CQE handlers.
Helper functions for asynchronous operations.
#define CONDY_FILE_INDEX_ALLOC
Placeholder to let io_uring allocate a direct file descriptor.
Definition helpers.hpp:20
The main namespace for the Condy library.
Definition condy.hpp:28
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_fixed_fd_send(FdTable &dst, int source_fd, int target_fd, unsigned int flags)
See io_uring_prep_msg_ring_fd.
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.
Support for io_uring provided buffers.