William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 1 | #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 | |
| 11 | namespace stdplus |
| 12 | { |
| 13 | |
William A. Kennington III | 43e3818 | 2021-08-19 17:29:48 -0700 | [diff] [blame] | 14 | __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 III | 8056259 | 2021-08-19 18:42:04 -0700 | [diff] [blame] | 22 | IoUring::IoUring(size_t queue_size, int flags) |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 23 | { |
William A. Kennington III | 8056259 | 2021-08-19 18:42:04 -0700 | [diff] [blame] | 24 | CHECK_RET(io_uring_queue_init(queue_size, &ring, flags), |
| 25 | "io_uring_queue_init"); |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 26 | } |
| 27 | |
Jerry Zhu | 8efeaa3 | 2021-08-10 14:54:00 +0000 | [diff] [blame] | 28 | IoUring::IoUring(size_t queue_size, io_uring_params& params) |
| 29 | { |
| 30 | CHECK_RET(io_uring_queue_init_params(queue_size, &ring, ¶ms), |
| 31 | "io_uring_queue_init_params"); |
| 32 | } |
| 33 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 34 | IoUring::~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 III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 45 | IoUring::FileHandle::FileHandle(unsigned slot, IoUring& ring) : |
| 46 | slot(slot, &ring) |
Patrick Williams | d1984dd | 2023-05-10 16:12:44 -0500 | [diff] [blame] | 47 | {} |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 48 | |
| 49 | void IoUring::FileHandle::drop(unsigned&& slot, IoUring*& ring) |
| 50 | { |
| 51 | ring->updateFile(slot, -1); |
| 52 | } |
| 53 | |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 54 | void 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 III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 66 | [[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 III | 7fc86da | 2021-08-19 17:47:40 -0700 | [diff] [blame] | 79 | files.resize(std::max<size_t>(7, files.size() * 2 + 1), -1); |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 80 | setFile(slot, fd); |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 81 | 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 III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 86 | io_uring_sqe& IoUring::getSQE() |
| 87 | { |
| 88 | return *CHECK_ERRNO(io_uring_get_sqe(&ring), "io_uring_get_sqe"); |
| 89 | } |
| 90 | |
| 91 | void 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 | |
| 108 | void IoUring::cancelHandler(CQEHandler& h) |
| 109 | { |
| 110 | io_uring_prep_cancel(&getSQE(), &h, 0); |
| 111 | submit(); |
| 112 | } |
| 113 | |
| 114 | void IoUring::submit() |
| 115 | { |
| 116 | CHECK_RET(io_uring_submit(&ring), "io_uring_submit"); |
| 117 | } |
| 118 | |
| 119 | void 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 III | 43e3818 | 2021-08-19 17:29:48 -0700 | [diff] [blame] | 130 | void IoUring::wait() |
| 131 | { |
| 132 | io_uring_cqe* cqe; |
| 133 | CHECK_RET(io_uring_wait_cqe(&ring, &cqe), "io_uring_wait_cqe"); |
| 134 | } |
| 135 | |
| 136 | void 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 III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 144 | ManagedFd& IoUring::getEventFd() |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 145 | { |
| 146 | if (event_fd) |
| 147 | { |
| 148 | return *event_fd; |
| 149 | } |
William A. Kennington III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 150 | ManagedFd efd(CHECK_RET(eventfd(0, EFD_NONBLOCK), "eventfd")); |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 151 | CHECK_RET(io_uring_register_eventfd(&ring, efd.get()), |
| 152 | "io_uring_register_eventfd"); |
| 153 | return *(event_fd = std::move(efd)); |
| 154 | } |
| 155 | |
| 156 | void IoUring::processEvents() |
| 157 | { |
| 158 | auto& efd = getEventFd(); |
| 159 | std::byte b[8]; |
William A. Kennington III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 160 | while (!fd::read(efd, b).empty()) |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 161 | { |
| 162 | process(); |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | void 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 III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 181 | void 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 III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 194 | void IoUring::updateFile(unsigned slot, int fd) |
| 195 | { |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 196 | setFile(slot, fd); |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 197 | CHECK_RET(io_uring_register_files_update(&ring, slot, &files[slot], 1), |
| 198 | "io_uring_register_files_update"); |
| 199 | } |
| 200 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 201 | } // namespace stdplus |