Condy v1.1.0
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"
11#include "condy/utils.hpp"
12#include <cassert>
13#include <cerrno>
14#include <cstddef>
15#include <cstring>
16
17namespace condy {
18
24class FdTable {
25public:
26 FdTable(io_uring &ring) : ring_(ring) {}
27
28 FdTable(const FdTable &) = delete;
29 FdTable &operator=(const FdTable &) = delete;
30 FdTable(FdTable &&) = delete;
31 FdTable &operator=(FdTable &&) = delete;
32
33public:
39 int init(size_t capacity) {
40 return io_uring_register_files_sparse(&ring_, capacity);
41 }
42
47 int destroy() { return io_uring_unregister_files(&ring_); }
48
56 int update(unsigned index_base, const int *fds, unsigned nr_fds) {
57 return io_uring_register_files_update(&ring_, index_base, fds, nr_fds);
58 }
59
69 template <typename Func> void set_fd_accepter(Func &&accepter) {
70 fd_accepter_ = std::forward<Func>(accepter);
71 }
72
79 int set_file_alloc_range(unsigned offset, unsigned size) {
80 return io_uring_register_file_alloc_range(&ring_, offset, size);
81 }
82
83private:
84 std::function<void(int32_t)> fd_accepter_ = nullptr;
85 io_uring &ring_;
86
87 friend class Runtime;
88 friend auto async_fixed_fd_send(FdTable &dst, int source_fd, int target_fd,
89 unsigned int flags);
90};
91
97class BufferTable {
98public:
99 BufferTable(io_uring &ring) : ring_(ring) {}
100
101 BufferTable(const BufferTable &) = delete;
102 BufferTable &operator=(const BufferTable &) = delete;
103 BufferTable(BufferTable &&) = delete;
104 BufferTable &operator=(BufferTable &&) = delete;
105
106public:
112 int init(size_t capacity) {
113 int r = io_uring_register_buffers_sparse(&ring_, capacity);
114 if (r < 0) {
115 return r;
116 }
117 initialized_ = true;
118 return r;
119 }
120
125 int destroy() {
126 initialized_ = false;
127 return io_uring_unregister_buffers(&ring_);
128 }
129
137 int update(unsigned index_base, const iovec *vecs, unsigned nr_vecs) {
138 return io_uring_register_buffers_update_tag(&ring_, index_base, vecs,
139 nullptr, nr_vecs);
140 }
141
142#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
143
152 int clone_buffers(BufferTable &src, unsigned int dst_off = 0,
153 unsigned int src_off = 0, unsigned int nr = 0) {
154 auto *src_ring = &src.ring_;
155 auto *dst_ring = &ring_;
156 unsigned int flags = 0;
157 if (initialized_) {
158 flags |= IORING_REGISTER_DST_REPLACE;
159 }
160 int r = __io_uring_clone_buffers_offset(dst_ring, src_ring, dst_off,
161 src_off, nr, flags);
162 if (r < 0) {
163 return r;
164 }
165 initialized_ = true;
166 return r;
167 }
168#endif
169
170private:
171 io_uring &ring_;
172 bool initialized_ = false;
173};
174
181class RingSettings {
182public:
183 RingSettings(io_uring &ring) : ring_(ring) {}
184
185 ~RingSettings() {
186 if (probe_) {
187 io_uring_free_probe(probe_);
188 probe_ = nullptr;
189 }
190 }
191
192 RingSettings(const RingSettings &) = delete;
193 RingSettings &operator=(const RingSettings &) = delete;
194 RingSettings(RingSettings &&) = delete;
195 RingSettings &operator=(RingSettings &&) = delete;
196
197public:
202 int apply_personality() { return io_uring_register_personality(&ring_); }
207 int remove_personality(int id) {
208 return io_uring_unregister_personality(&ring_, id);
209 }
210
217 int set_restrictions(io_uring_restriction *res, unsigned int nr_res) {
218 return io_uring_register_restrictions(&ring_, res, nr_res);
219 }
220
227 int apply_iowq_aff(size_t cpusz, const cpu_set_t *mask) {
228 return io_uring_register_iowq_aff(&ring_, cpusz, mask);
229 }
230
234 int remove_iowq_aff() { return io_uring_unregister_iowq_aff(&ring_); }
235
242 int set_iowq_max_workers(unsigned int *values) {
243 return io_uring_register_iowq_max_workers(&ring_, values);
244 }
245
251 io_uring_probe *get_probe() {
252 if (probe_) {
253 return probe_;
254 }
255 probe_ = io_uring_get_probe_ring(&ring_);
256 return probe_;
257 }
258
263 uint32_t get_features() const { return features_; }
264
265#if !IO_URING_CHECK_VERSION(2, 6) // >= 2.6
271 int apply_napi(io_uring_napi *napi) {
272 return io_uring_register_napi(&ring_, napi);
273 }
274
278 int remove_napi(io_uring_napi *napi = nullptr) {
279 return io_uring_unregister_napi(&ring_, napi);
280 }
281#endif
282
283#if !IO_URING_CHECK_VERSION(2, 8) // >= 2.8
289 int set_clock(io_uring_clock_register *clock_reg) {
290 return io_uring_register_clock(&ring_, clock_reg);
291 }
292#endif
293
294#if !IO_URING_CHECK_VERSION(2, 9) // >= 2.9
300 int set_rings_size(io_uring_params *params) {
301 return io_uring_resize_rings(&ring_, params);
302 }
303#endif
304
305#if !IO_URING_CHECK_VERSION(2, 10) // >= 2.10
311 int set_iowait(bool enable_iowait) {
312 return io_uring_set_iowait(&ring_, enable_iowait);
313 }
314#endif
315
316private:
317 io_uring &ring_;
318 io_uring_probe *probe_ = nullptr;
319 uint32_t features_ = 0;
320
321 friend class Ring;
322};
323
324class Ring {
325public:
326 Ring() = default;
327 ~Ring() { destroy(); }
328
329 Ring(const Ring &) = delete;
330 Ring &operator=(const Ring &) = delete;
331 Ring(Ring &&) = delete;
332 Ring &operator=(Ring &&) = delete;
333
334public:
335 int init(unsigned int entries, io_uring_params *params,
336 [[maybe_unused]] void *buf = nullptr,
337 [[maybe_unused]] size_t buf_size = 0) {
338 int r;
339 assert(!initialized_);
340#if !IO_URING_CHECK_VERSION(2, 5) // >= 2.5
341 if (params->flags & IORING_SETUP_NO_MMAP) {
342 r = io_uring_queue_init_mem(entries, &ring_, params, buf, buf_size);
343 } else
344#endif
345 r = io_uring_queue_init_params(entries, &ring_, params);
346 if (r < 0) {
347 return r;
348 }
349 settings_.features_ = params->features;
350 sqpoll_mode_ = (params->flags & IORING_SETUP_SQPOLL) != 0;
351 initialized_ = true;
352 return r;
353 }
354
355 void destroy() {
356 if (initialized_) {
357 io_uring_queue_exit(&ring_);
358 initialized_ = false;
359 }
360 }
361
362 void submit() { io_uring_submit(&ring_); }
363
364 template <typename Func> size_t reap_completions_wait(Func &&process_func) {
365 unsigned head;
366 io_uring_cqe *cqe;
367 size_t reaped = 0;
368 do {
369 int r = io_uring_submit_and_wait(&ring_, 1);
370 if (r >= 0) [[likely]] {
371 break;
372 } else if (r == -EINTR) {
373 continue;
374 } else {
375 throw make_system_error("io_uring_submit_and_wait", -r);
376 }
377 } while (true);
378
379 io_uring_for_each_cqe(&ring_, head, cqe) {
380 process_func(cqe);
381 reaped++;
382 }
383 io_uring_cq_advance(&ring_, reaped);
384 return reaped;
385 }
386
387 template <typename Func> size_t reap_completions(Func &&process_func) {
388 unsigned head;
389 io_uring_cqe *cqe;
390 size_t reaped = 0;
391
392 if (io_uring_peek_cqe(&ring_, &cqe) == 0) {
393 io_uring_for_each_cqe(&ring_, head, cqe) {
394 process_func(cqe);
395 reaped++;
396 }
397 io_uring_cq_advance(&ring_, reaped);
398 }
399
400 return reaped;
401 }
402
403 void reserve_space(size_t n) {
404 size_t space_left;
405 do {
406 space_left = io_uring_sq_space_left(&ring_);
407 if (space_left >= n) {
408 return;
409 }
410 submit();
411 } while (true);
412 }
413
414 io_uring *ring() { return &ring_; }
415
416 FdTable &fd_table() { return fd_table_; }
417
418 BufferTable &buffer_table() { return buffer_table_; }
419
420 RingSettings &settings() { return settings_; }
421
422 io_uring_sqe *get_sqe() {
423 [[maybe_unused]] int r;
424 io_uring_sqe *sqe;
425 do {
426 sqe = io_uring_get_sqe(&ring_);
427 if (sqe) {
428 break;
429 }
430 r = io_uring_submit(&ring_);
431 assert(r >= 0);
432 if (sqpoll_mode_) {
433 r = io_uring_sqring_wait(&ring_);
434 assert(r >= 0);
435 }
436 } while (true);
437 return sqe;
438 }
439
440private:
441 bool initialized_ = false;
442 io_uring ring_;
443 bool sqpoll_mode_ = false;
444
445 FdTable fd_table_{ring_};
446 BufferTable buffer_table_{ring_};
447 RingSettings settings_{ring_};
448};
449
450} // namespace condy
int destroy()
Destroy the buffer table.
Definition ring.hpp:125
int update(unsigned index_base, const iovec *vecs, unsigned nr_vecs)
Update the buffer table starting from the given index.
Definition ring.hpp:137
int init(size_t capacity)
Initialize the buffer table with the given capacity.
Definition ring.hpp:112
int clone_buffers(BufferTable &src, unsigned int dst_off=0, unsigned int src_off=0, unsigned int nr=0)
Clone buffers from another BufferTable into this one.
Definition ring.hpp:152
File descriptor table for io_uring.
Definition ring.hpp:24
void set_fd_accepter(Func &&accepter)
Set the accepter function for incoming file descriptors.
Definition ring.hpp:69
int update(unsigned index_base, const int *fds, unsigned nr_fds)
Update the file descriptor table starting from the given index.
Definition ring.hpp:56
int init(size_t capacity)
Initialize the file descriptor table with the given capacity.
Definition ring.hpp:39
int destroy()
Destroy the file descriptor table.
Definition ring.hpp:47
int set_file_alloc_range(unsigned offset, unsigned size)
Set the file allocation range for the fd table.
Definition ring.hpp:79
friend auto async_fixed_fd_send(FdTable &dst, int source_fd, int target_fd, unsigned int flags)
See io_uring_prep_msg_ring_fd.
Definition async_operations.hpp:898
int set_clock(io_uring_clock_register *clock_reg)
Set the clock registration for the io_uring instance.
Definition ring.hpp:289
uint32_t get_features() const
Get the supported features of the ring.
Definition ring.hpp:263
int remove_iowq_aff()
Remove I/O worker queue affinity settings.
Definition ring.hpp:234
int set_iowait(bool enable_iowait)
Enable or disable iowait for the io_uring instance.
Definition ring.hpp:311
int apply_iowq_aff(size_t cpusz, const cpu_set_t *mask)
Apply I/O worker queue affinity settings.
Definition ring.hpp:227
io_uring_probe * get_probe()
Get the io_uring probe for the ring.
Definition ring.hpp:251
int set_restrictions(io_uring_restriction *res, unsigned int nr_res)
Set restrictions for the io_uring instance.
Definition ring.hpp:217
int apply_personality()
Apply a personality to the io_uring instance.
Definition ring.hpp:202
int remove_personality(int id)
Remove a personality from the io_uring instance.
Definition ring.hpp:207
int set_iowq_max_workers(unsigned int *values)
Set the maximum number of I/O workers.
Definition ring.hpp:242
int remove_napi(io_uring_napi *napi=nullptr)
Remove NAPI settings from the io_uring instance.
Definition ring.hpp:278
int apply_napi(io_uring_napi *napi)
Apply NAPI settings to the io_uring instance.
Definition ring.hpp:271
int set_rings_size(io_uring_params *params)
Resize the rings of the io_uring instance.
Definition ring.hpp:300
The event loop runtime for executing asynchronous.
Definition runtime.hpp:76
The main namespace for the Condy library.
Definition condy.hpp:28
Internal utility classes and functions used by Condy.