1 // 2 // Copyright (C) 2022 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef __IO_URING_CPP_H 18 #define __IO_URING_CPP_H 19 20 #include <errno.h> 21 #include <string.h> 22 23 #include <sys/uio.h> 24 25 #include <algorithm> 26 #include <memory> 27 #include <optional> 28 #include <variant> 29 30 #include "IoUringCQE.h" 31 #include "IoUringSQE.h" 32 33 namespace io_uring_cpp { 34 35 template <typename Err, typename Res> 36 struct [[nodiscard]] Result : public std::variant<Err, Res> { IsOkResult37 constexpr bool IsOk() const { return std::holds_alternative<Res>(*this); } IsErrResult38 constexpr bool IsErr() const { return std::holds_alternative<Err>(*this); } GetErrorResult39 constexpr Err GetError() const { return std::get<Err>(*this); } GetResultResult40 constexpr const Res& GetResult() const& { return std::get<Res>(*this); } GetResultResult41 constexpr Res&& GetResult() && { return std::get<Res>(*this); } 42 }; 43 44 class IoUringInterface { 45 public: ~IoUringInterface()46 virtual ~IoUringInterface() {} 47 // Registration helpers 48 // Register a fixed set of buffers to kernel. 49 virtual Errno RegisterBuffers(const struct iovec* iovecs, 50 size_t iovec_size) = 0; 51 virtual Errno UnregisterBuffers() = 0; 52 53 // Register a set of file descriptors to kernel. 54 virtual Errno RegisterFiles(const int* files, size_t files_size) = 0; 55 virtual Errno UnregisterFiles() = 0; 56 57 // Prepare read to a registered buffer. This does not submit the operation 58 // to the kernel. For that, call |IoUringInterface::Submit()| 59 virtual IoUringSQE PrepReadFixed( 60 int fd, void* buf, unsigned nbytes, uint64_t offset, int buf_index) = 0; 61 62 // Append a submission entry into this io_uring. This does not submit the 63 // operation to the kernel. For that, call |IoUringInterface::Submit()| 64 virtual IoUringSQE PrepRead(int fd, void *buf, unsigned nbytes, 65 uint64_t offset) = 0; 66 // Caller is responsible for making sure the input memory is available until 67 // this write operation completes. 68 virtual IoUringSQE PrepWrite(int fd, const void *buf, unsigned nbytes, 69 uint64_t offset) = 0; 70 71 // Return number of SQEs available in the queue. If this is 0, subsequent 72 // calls to Prep*() functions will fail. 73 virtual size_t SQELeft() const = 0; 74 // Return number of SQEs currently in the queue. SQEs already submitted would 75 // not be counted. 76 virtual size_t SQEReady() const = 0; 77 78 // Ring operations 79 virtual IoUringSubmitResult Submit() = 0; 80 // Submit and block until |completions| number of CQEs are available 81 virtual IoUringSubmitResult SubmitAndWait(size_t completions) = 0; 82 virtual Result<Errno, IoUringCQE> PopCQE() = 0; 83 virtual Result<Errno, std::vector<IoUringCQE>> PopCQE(unsigned int count) = 0; 84 virtual Result<Errno, IoUringCQE> PeekCQE() = 0; 85 86 static std::unique_ptr<IoUringInterface> CreateLinuxIoUring(int queue_depth, 87 int flags); 88 }; 89 90 } // namespace io_uring_cpp 91 92 #endif 93