blob: 0e6a7b498aa00e17e414d31ae1defbba6b225f3c [file] [log] [blame]
William A. Kennington III5c20da22021-06-18 16:44:55 -07001#include <liburing.h>
2#include <sys/eventfd.h>
3
4#include <stdplus/fd/managed.hpp>
5#include <stdplus/fd/ops.hpp>
6#include <stdplus/io_uring.hpp>
7#include <stdplus/util/cexec.hpp>
8
9#include <algorithm>
10
11namespace stdplus
12{
13
William A. Kennington III43e38182021-08-19 17:29:48 -070014__kernel_timespec chronoToKTS(std::chrono::nanoseconds t) noexcept
15{
16 __kernel_timespec ts;
17 ts.tv_sec = std::chrono::floor<std::chrono::seconds>(t).count();
18 ts.tv_nsec = (t % std::chrono::seconds(1)).count();
19 return ts;
20}
21
William A. Kennington III80562592021-08-19 18:42:04 -070022IoUring::IoUring(size_t queue_size, int flags)
William A. Kennington III5c20da22021-06-18 16:44:55 -070023{
William A. Kennington III80562592021-08-19 18:42:04 -070024 CHECK_RET(io_uring_queue_init(queue_size, &ring, flags),
25 "io_uring_queue_init");
William A. Kennington III5c20da22021-06-18 16:44:55 -070026}
27
Jerry Zhu8efeaa32021-08-10 14:54:00 +000028IoUring::IoUring(size_t queue_size, io_uring_params& params)
29{
30 CHECK_RET(io_uring_queue_init_params(queue_size, &ring, &params),
31 "io_uring_queue_init_params");
32}
33
William A. Kennington III5c20da22021-06-18 16:44:55 -070034IoUring::~IoUring()
35{
36 io_uring_queue_exit(&ring);
37 io_uring_cqe cqe{};
38 cqe.res = -ECANCELED;
39 for (auto h : handlers)
40 {
41 h->handleCQE(cqe);
42 }
43}
44
William A. Kennington IIIabc6be72021-08-17 01:58:27 -070045IoUring::FileHandle::FileHandle(unsigned slot, IoUring& ring) :
46 slot(slot, &ring)
Patrick Williamsd1984dd2023-05-10 16:12:44 -050047{}
William A. Kennington IIIabc6be72021-08-17 01:58:27 -070048
49void IoUring::FileHandle::drop(unsigned&& slot, IoUring*& ring)
50{
51 ring->updateFile(slot, -1);
52}
53
William A. Kennington III1afd7732021-08-20 00:49:10 -070054void IoUring::reserveFiles(size_t num)
55{
56 auto new_size = std::max<size_t>(7, num + filesAllocated);
57 if (files.size() < new_size)
58 {
59 io_uring_unregister_files(&ring);
60 files.resize(new_size, -1);
61 CHECK_RET(io_uring_register_files(&ring, files.data(), files.size()),
62 "io_uring_register_files");
63 }
64}
65
William A. Kennington IIIabc6be72021-08-17 01:58:27 -070066[[nodiscard]] IoUring::FileHandle IoUring::registerFile(int fd)
67{
68 unsigned slot = 0;
69 for (; slot < files.size(); slot++)
70 {
71 if (files[slot] == -1)
72 {
73 updateFile(slot, fd);
74 return FileHandle(slot, *this);
75 }
76 }
77
78 io_uring_unregister_files(&ring);
William A. Kennington III7fc86da2021-08-19 17:47:40 -070079 files.resize(std::max<size_t>(7, files.size() * 2 + 1), -1);
William A. Kennington III1afd7732021-08-20 00:49:10 -070080 setFile(slot, fd);
William A. Kennington IIIabc6be72021-08-17 01:58:27 -070081 CHECK_RET(io_uring_register_files(&ring, files.data(), files.size()),
82 "io_uring_register_files");
83 return FileHandle(slot, *this);
84}
85
William A. Kennington III5c20da22021-06-18 16:44:55 -070086io_uring_sqe& IoUring::getSQE()
87{
88 return *CHECK_ERRNO(io_uring_get_sqe(&ring), "io_uring_get_sqe");
89}
90
91void IoUring::setHandler(io_uring_sqe& sqe, CQEHandler* h) noexcept
92{
93 auto oldh = reinterpret_cast<CQEHandler*>(sqe.user_data);
94 if (oldh == h)
95 {
96 return;
97 }
98 io_uring_cqe cqe{};
99 cqe.res = -ECANCELED;
100 dropHandler(oldh, cqe);
101 if (h != nullptr)
102 {
103 handlers.push_back(h);
104 }
105 io_uring_sqe_set_data(&sqe, h);
106}
107
108void IoUring::cancelHandler(CQEHandler& h)
109{
110 io_uring_prep_cancel(&getSQE(), &h, 0);
111 submit();
112}
113
114void IoUring::submit()
115{
116 CHECK_RET(io_uring_submit(&ring), "io_uring_submit");
117}
118
119void IoUring::process() noexcept
120{
121 io_uring_cqe* cqe;
122 while (io_uring_peek_cqe(&ring, &cqe) == 0)
123 {
124 auto h = reinterpret_cast<CQEHandler*>(cqe->user_data);
125 dropHandler(h, *cqe);
126 io_uring_cqe_seen(&ring, cqe);
127 }
128}
129
William A. Kennington III43e38182021-08-19 17:29:48 -0700130void IoUring::wait()
131{
132 io_uring_cqe* cqe;
133 CHECK_RET(io_uring_wait_cqe(&ring, &cqe), "io_uring_wait_cqe");
134}
135
136void IoUring::wait(std::chrono::nanoseconds timeout)
137{
138 io_uring_cqe* cqe;
139 auto kts = chronoToKTS(timeout);
140 CHECK_RET(io_uring_wait_cqe_timeout(&ring, &cqe, &kts),
141 "io_uring_wait_cqe_timeout");
142}
143
William A. Kennington IIIa4f71f92022-08-18 14:17:00 -0700144ManagedFd& IoUring::getEventFd()
William A. Kennington III5c20da22021-06-18 16:44:55 -0700145{
146 if (event_fd)
147 {
148 return *event_fd;
149 }
William A. Kennington IIIa4f71f92022-08-18 14:17:00 -0700150 ManagedFd efd(CHECK_RET(eventfd(0, EFD_NONBLOCK), "eventfd"));
William A. Kennington III5c20da22021-06-18 16:44:55 -0700151 CHECK_RET(io_uring_register_eventfd(&ring, efd.get()),
152 "io_uring_register_eventfd");
153 return *(event_fd = std::move(efd));
154}
155
156void IoUring::processEvents()
157{
158 auto& efd = getEventFd();
159 std::byte b[8];
William A. Kennington IIIa4f71f92022-08-18 14:17:00 -0700160 while (!fd::read(efd, b).empty())
William A. Kennington III5c20da22021-06-18 16:44:55 -0700161 {
162 process();
163 }
164}
165
166void IoUring::dropHandler(CQEHandler* h, io_uring_cqe& cqe) noexcept
167{
168 if (h == nullptr)
169 {
170 return;
171 }
172 auto it = std::find(handlers.begin(), handlers.end(), h);
173 if (it != handlers.end() - 1)
174 {
175 std::swap(*it, handlers.back());
176 }
177 handlers.pop_back();
178 h->handleCQE(cqe);
179}
180
William A. Kennington III1afd7732021-08-20 00:49:10 -0700181void IoUring::setFile(unsigned slot, int fd) noexcept
182{
183 if (files[slot] == -1 && files[slot] != fd)
184 {
185 filesAllocated++;
186 }
187 else if (fd == -1 && files[slot] != fd)
188 {
189 filesAllocated--;
190 }
191 files[slot] = fd;
192}
193
William A. Kennington IIIabc6be72021-08-17 01:58:27 -0700194void IoUring::updateFile(unsigned slot, int fd)
195{
William A. Kennington III1afd7732021-08-20 00:49:10 -0700196 setFile(slot, fd);
William A. Kennington IIIabc6be72021-08-17 01:58:27 -0700197 CHECK_RET(io_uring_register_files_update(&ring, slot, &files[slot], 1),
198 "io_uring_register_files_update");
199}
200
William A. Kennington III5c20da22021-06-18 16:44:55 -0700201} // namespace stdplus