// SPDX-License-Identifier: BSD-2-Clause // Copyright CM4all GmbH // author: Max Kellermann #pragma once #include "io/FileDescriptor.hxx" #include namespace Uring { /** * Low-level C++ wrapper for a `struct io_uring`. It provides simple * wrappers to liburing functions and throws std::system_error on * errors. */ class Ring { struct io_uring ring; public: /** * Construct the io_uring using io_uring_queue_init(). * * Throws on error. */ Ring(unsigned entries, unsigned flags); /** * Construct the io_uring using io_uring_queue_init(). * * Throws on error. * * @param params initialization parameters; will also be * written to by this constructor */ Ring(unsigned entries, struct io_uring_params ¶ms); ~Ring() noexcept { io_uring_queue_exit(&ring); } Ring(const Ring &) = delete; Ring &operator=(const Ring &) = delete; /** * Returns the io_uring file descriptor. */ FileDescriptor GetFileDescriptor() const noexcept { return FileDescriptor(ring.ring_fd); } /** * Wrapper for io_uring_register_iowq_max_workers(). * * Throws on error. */ void SetMaxWorkers(unsigned values[2]); /** * This overload constructs an array for * io_uring_register_iowq_max_workers() and discards the * output values. */ void SetMaxWorkers(unsigned bounded, unsigned unbounded) { unsigned values[2] = {bounded, unbounded}; SetMaxWorkers(values); } /** * Returns a submit queue entry or nullptr if the submit queue * is full. */ struct io_uring_sqe *GetSubmitEntry() noexcept { return io_uring_get_sqe(&ring); } /** * Submit all pending entries from the submit queue to the * kernel using io_uring_submit(). * * Throws on error. * * @see io_uring_submit() */ void Submit(); /** * Like Submit(), but also flush completions. * * @see io_uring_submit_and_get_events() */ void SubmitAndGetEvents(); /** * Waits for one completion. * * Throws on error. * * @return a completion queue entry or nullptr on EAGAIN */ struct io_uring_cqe *WaitCompletion(); /** * Submit requests and wait for one completion (or a timeout). * Wrapper for io_uring_submit_and_wait_timeout(). * * Throws on error. * * @return a completion queue entry or nullptr on EAGAIN/ETIME */ struct io_uring_cqe *SubmitAndWaitCompletion(struct __kernel_timespec *timeout); /** * Peek one completion (non-blocking). * * Throws on error. * * @return a completion queue entry or nullptr on EAGAIN */ struct io_uring_cqe *PeekCompletion(); /** * Mark one completion event as consumed. */ void SeenCompletion(struct io_uring_cqe &cqe) noexcept { io_uring_cqe_seen(&ring, &cqe); } /** * Invoke a function with a reference to each completion (but * do not mark it "seen" or advance the completion queue * head). */ unsigned ForEachCompletion(struct io_uring_cqe *cqe, std::invocable auto f) noexcept { unsigned dummy, n = 0; io_uring_for_each_cqe(&ring, dummy, cqe) { ++n; f(*cqe); } return n; } /** * Like ForEachCompletion(), but advance the completion queue * head. */ unsigned VisitCompletions(struct io_uring_cqe *cqe, std::invocable auto f) noexcept { unsigned n = ForEachCompletion(cqe, f); if (n > 0) io_uring_cq_advance(&ring, n); return n; } }; } // namespace Uring