Condy v1.8
C++ Asynchronous System Call Layer for Linux
Loading...
Searching...
No Matches
ring.hpp
Go to the documentation of this file.
1
7
8#pragma once
9
10#include "condy/condy_uring.hpp"
12#include <cassert>
13#include <cerrno>
14#include <cstddef>
15#include <cstring>
16
17namespace condy {
18namespace detail {
19
20class Ring {
21public:
22 Ring(unsigned int entries, io_uring_params *params,
23 [[maybe_unused]] void *buf, [[maybe_unused]] size_t buf_size,
24 size_t submit_batch)
25 : submit_batch_(submit_batch) {
26 int r;
27#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
28 if (params->flags & IORING_SETUP_NO_MMAP) {
29 r = io_uring_queue_init_mem(entries, &ring_, params, buf, buf_size);
30 } else {
31 r = io_uring_queue_init_params(entries, &ring_, params);
32 }
33#else
34 r = io_uring_queue_init_params(entries, &ring_, params);
35#endif
36 if (r < 0) {
37 throw make_system_error("io_uring_queue_init_params", -r);
38 }
39 }
40
41 ~Ring() { io_uring_queue_exit(&ring_); }
42
43 CONDY_DELETE_COPY_MOVE(Ring);
44
45public:
46 void submit() noexcept {
47 maybe_submit_count_ = 0;
48 io_uring_submit(&ring_);
49 }
50
51 void maybe_submit() noexcept {
52 maybe_submit_count_++;
53 if (maybe_submit_count_ >= submit_batch_) {
54 submit();
55 }
56 }
57
58 template <typename Func>
59 ssize_t reap_completions_wait(Func &&process_func) noexcept {
60 unsigned head;
61 io_uring_cqe *cqe;
62 ssize_t reaped = 0;
63 do {
64 int r = io_uring_submit_and_wait(&ring_, 1);
65 if (r >= 0) [[likely]] {
66 maybe_submit_count_ = 0;
67 break;
68 } else if (r == -EINTR) {
69 continue;
70 } else {
71 return r;
72 }
73 } while (true);
74
75 io_uring_for_each_cqe(&ring_, head, cqe) {
76 process_func(cqe);
77#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
78 reaped += io_uring_cqe_nr(cqe);
79#else
80 reaped++;
81#endif
82 }
83 io_uring_cq_advance(&ring_, reaped);
84 return reaped;
85 }
86
87 template <typename Func>
88 ssize_t reap_completions(Func &&process_func) noexcept {
89 io_uring_cqe *cqe;
90 int r = io_uring_peek_cqe(&ring_, &cqe);
91 if (r == -EAGAIN) {
92 return 0;
93 } else if (r < 0) {
94 return r;
95 }
96
97 unsigned head;
98 ssize_t reaped = 0;
99 io_uring_for_each_cqe(&ring_, head, cqe) {
100 process_func(cqe);
101#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
102 reaped += io_uring_cqe_nr(cqe);
103#else
104 reaped++;
105#endif
106 }
107 io_uring_cq_advance(&ring_, reaped);
108 return reaped;
109 }
110
111 void reserve_space(size_t n) noexcept {
112 size_t space_left;
113 do {
114 space_left = io_uring_sq_space_left(&ring_);
115 if (space_left >= n) {
116 return;
117 }
118 submit();
119 } while (true);
120 }
121
122 io_uring *ring() noexcept { return &ring_; }
123
124 io_uring_sqe *get_sqe() noexcept { return get_sqe_<io_uring_get_sqe>(); }
125
126#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
127 io_uring_sqe *get_sqe128() noexcept {
128 if (ring_.flags & (IORING_SETUP_SQE128 | IORING_SETUP_SQE_MIXED))
129 [[likely]] {
130 return get_sqe_<io_uring_get_sqe128>();
131 }
132 return nullptr;
133 }
134#endif
135
136 bool check_cqe32([[maybe_unused]] io_uring_cqe *cqe) const noexcept {
137 auto ring_flags = ring_.flags;
138 if (ring_flags & IORING_SETUP_CQE32) {
139 return true;
140 }
141#if !IO_URING_CHECK_VERSION(2, 13) // >= 2.13
142 if (ring_flags & IORING_SETUP_CQE_MIXED) {
143 return cqe->flags & IORING_CQE_F_32;
144 }
145#endif
146 return false;
147 }
148
149private:
150 template <io_uring_sqe *(*get_sqe)(struct io_uring *)>
151 io_uring_sqe *get_sqe_() noexcept {
152 [[maybe_unused]] int r;
153 io_uring_sqe *sqe;
154 do {
155 sqe = get_sqe(&ring_);
156 if (sqe) {
157 break;
158 }
159 submit();
160 if (ring_.flags & IORING_SETUP_SQPOLL) {
161 r = io_uring_sqring_wait(&ring_);
162 assert(r >= 0);
163 }
164 } while (true);
165 return sqe;
166 }
167
168private:
169 io_uring ring_;
170 size_t submit_batch_;
171 size_t maybe_submit_count_ = 0;
172};
173
174} // namespace detail
175} // namespace condy
The main namespace for the Condy library.
Definition condy.hpp:37
Internal utility classes and functions used by Condy.