William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 1 | #include <liburing.h> |
Jerry Zhu | 8efeaa3 | 2021-08-10 14:54:00 +0000 | [diff] [blame] | 2 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 3 | #include <sys/eventfd.h> |
| 4 | |
| 5 | #include <stdplus/fd/managed.hpp> |
| 6 | #include <stdplus/fd/ops.hpp> |
| 7 | #include <stdplus/io_uring.hpp> |
| 8 | #include <stdplus/util/cexec.hpp> |
| 9 | |
| 10 | #include <algorithm> |
| 11 | |
| 12 | namespace stdplus |
| 13 | { |
| 14 | |
William A. Kennington III | 43e3818 | 2021-08-19 17:29:48 -0700 | [diff] [blame] | 15 | __kernel_timespec chronoToKTS(std::chrono::nanoseconds t) noexcept |
| 16 | { |
| 17 | __kernel_timespec ts; |
| 18 | ts.tv_sec = std::chrono::floor<std::chrono::seconds>(t).count(); |
| 19 | ts.tv_nsec = (t % std::chrono::seconds(1)).count(); |
| 20 | return ts; |
| 21 | } |
| 22 | |
William A. Kennington III | 8056259 | 2021-08-19 18:42:04 -0700 | [diff] [blame] | 23 | IoUring::IoUring(size_t queue_size, int flags) |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 24 | { |
William A. Kennington III | 8056259 | 2021-08-19 18:42:04 -0700 | [diff] [blame] | 25 | CHECK_RET(io_uring_queue_init(queue_size, &ring, flags), |
| 26 | "io_uring_queue_init"); |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 27 | } |
| 28 | |
Jerry Zhu | 8efeaa3 | 2021-08-10 14:54:00 +0000 | [diff] [blame] | 29 | IoUring::IoUring(size_t queue_size, io_uring_params& params) |
| 30 | { |
| 31 | CHECK_RET(io_uring_queue_init_params(queue_size, &ring, ¶ms), |
| 32 | "io_uring_queue_init_params"); |
| 33 | } |
| 34 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 35 | IoUring::~IoUring() |
| 36 | { |
| 37 | io_uring_queue_exit(&ring); |
| 38 | io_uring_cqe cqe{}; |
| 39 | cqe.res = -ECANCELED; |
| 40 | for (auto h : handlers) |
| 41 | { |
| 42 | h->handleCQE(cqe); |
| 43 | } |
| 44 | } |
| 45 | |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 46 | IoUring::FileHandle::FileHandle(unsigned slot, IoUring& ring) : |
| 47 | slot(slot, &ring) |
| 48 | { |
| 49 | } |
| 50 | |
| 51 | void IoUring::FileHandle::drop(unsigned&& slot, IoUring*& ring) |
| 52 | { |
| 53 | ring->updateFile(slot, -1); |
| 54 | } |
| 55 | |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 56 | void IoUring::reserveFiles(size_t num) |
| 57 | { |
| 58 | auto new_size = std::max<size_t>(7, num + filesAllocated); |
| 59 | if (files.size() < new_size) |
| 60 | { |
| 61 | io_uring_unregister_files(&ring); |
| 62 | files.resize(new_size, -1); |
| 63 | CHECK_RET(io_uring_register_files(&ring, files.data(), files.size()), |
| 64 | "io_uring_register_files"); |
| 65 | } |
| 66 | } |
| 67 | |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 68 | [[nodiscard]] IoUring::FileHandle IoUring::registerFile(int fd) |
| 69 | { |
| 70 | unsigned slot = 0; |
| 71 | for (; slot < files.size(); slot++) |
| 72 | { |
| 73 | if (files[slot] == -1) |
| 74 | { |
| 75 | updateFile(slot, fd); |
| 76 | return FileHandle(slot, *this); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | io_uring_unregister_files(&ring); |
William A. Kennington III | 7fc86da | 2021-08-19 17:47:40 -0700 | [diff] [blame] | 81 | 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] | 82 | setFile(slot, fd); |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 83 | CHECK_RET(io_uring_register_files(&ring, files.data(), files.size()), |
| 84 | "io_uring_register_files"); |
| 85 | return FileHandle(slot, *this); |
| 86 | } |
| 87 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 88 | io_uring_sqe& IoUring::getSQE() |
| 89 | { |
| 90 | return *CHECK_ERRNO(io_uring_get_sqe(&ring), "io_uring_get_sqe"); |
| 91 | } |
| 92 | |
| 93 | void IoUring::setHandler(io_uring_sqe& sqe, CQEHandler* h) noexcept |
| 94 | { |
| 95 | auto oldh = reinterpret_cast<CQEHandler*>(sqe.user_data); |
| 96 | if (oldh == h) |
| 97 | { |
| 98 | return; |
| 99 | } |
| 100 | io_uring_cqe cqe{}; |
| 101 | cqe.res = -ECANCELED; |
| 102 | dropHandler(oldh, cqe); |
| 103 | if (h != nullptr) |
| 104 | { |
| 105 | handlers.push_back(h); |
| 106 | } |
| 107 | io_uring_sqe_set_data(&sqe, h); |
| 108 | } |
| 109 | |
| 110 | void IoUring::cancelHandler(CQEHandler& h) |
| 111 | { |
| 112 | io_uring_prep_cancel(&getSQE(), &h, 0); |
| 113 | submit(); |
| 114 | } |
| 115 | |
| 116 | void IoUring::submit() |
| 117 | { |
| 118 | CHECK_RET(io_uring_submit(&ring), "io_uring_submit"); |
| 119 | } |
| 120 | |
| 121 | void IoUring::process() noexcept |
| 122 | { |
| 123 | io_uring_cqe* cqe; |
| 124 | while (io_uring_peek_cqe(&ring, &cqe) == 0) |
| 125 | { |
| 126 | auto h = reinterpret_cast<CQEHandler*>(cqe->user_data); |
| 127 | dropHandler(h, *cqe); |
| 128 | io_uring_cqe_seen(&ring, cqe); |
| 129 | } |
| 130 | } |
| 131 | |
William A. Kennington III | 43e3818 | 2021-08-19 17:29:48 -0700 | [diff] [blame] | 132 | void IoUring::wait() |
| 133 | { |
| 134 | io_uring_cqe* cqe; |
| 135 | CHECK_RET(io_uring_wait_cqe(&ring, &cqe), "io_uring_wait_cqe"); |
| 136 | } |
| 137 | |
| 138 | void IoUring::wait(std::chrono::nanoseconds timeout) |
| 139 | { |
| 140 | io_uring_cqe* cqe; |
| 141 | auto kts = chronoToKTS(timeout); |
| 142 | CHECK_RET(io_uring_wait_cqe_timeout(&ring, &cqe, &kts), |
| 143 | "io_uring_wait_cqe_timeout"); |
| 144 | } |
| 145 | |
William A. Kennington III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 146 | ManagedFd& IoUring::getEventFd() |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 147 | { |
| 148 | if (event_fd) |
| 149 | { |
| 150 | return *event_fd; |
| 151 | } |
William A. Kennington III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 152 | ManagedFd efd(CHECK_RET(eventfd(0, EFD_NONBLOCK), "eventfd")); |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 153 | CHECK_RET(io_uring_register_eventfd(&ring, efd.get()), |
| 154 | "io_uring_register_eventfd"); |
| 155 | return *(event_fd = std::move(efd)); |
| 156 | } |
| 157 | |
| 158 | void IoUring::processEvents() |
| 159 | { |
| 160 | auto& efd = getEventFd(); |
| 161 | std::byte b[8]; |
William A. Kennington III | a4f71f9 | 2022-08-18 14:17:00 -0700 | [diff] [blame] | 162 | while (!fd::read(efd, b).empty()) |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 163 | { |
| 164 | process(); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | void IoUring::dropHandler(CQEHandler* h, io_uring_cqe& cqe) noexcept |
| 169 | { |
| 170 | if (h == nullptr) |
| 171 | { |
| 172 | return; |
| 173 | } |
| 174 | auto it = std::find(handlers.begin(), handlers.end(), h); |
| 175 | if (it != handlers.end() - 1) |
| 176 | { |
| 177 | std::swap(*it, handlers.back()); |
| 178 | } |
| 179 | handlers.pop_back(); |
| 180 | h->handleCQE(cqe); |
| 181 | } |
| 182 | |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 183 | void IoUring::setFile(unsigned slot, int fd) noexcept |
| 184 | { |
| 185 | if (files[slot] == -1 && files[slot] != fd) |
| 186 | { |
| 187 | filesAllocated++; |
| 188 | } |
| 189 | else if (fd == -1 && files[slot] != fd) |
| 190 | { |
| 191 | filesAllocated--; |
| 192 | } |
| 193 | files[slot] = fd; |
| 194 | } |
| 195 | |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 196 | void IoUring::updateFile(unsigned slot, int fd) |
| 197 | { |
William A. Kennington III | 1afd773 | 2021-08-20 00:49:10 -0700 | [diff] [blame] | 198 | setFile(slot, fd); |
William A. Kennington III | abc6be7 | 2021-08-17 01:58:27 -0700 | [diff] [blame] | 199 | CHECK_RET(io_uring_register_files_update(&ring, slot, &files[slot], 1), |
| 200 | "io_uring_register_files_update"); |
| 201 | } |
| 202 | |
William A. Kennington III | 5c20da2 | 2021-06-18 16:44:55 -0700 | [diff] [blame] | 203 | } // namespace stdplus |