diff --git a/emper/io.hpp b/emper/io.hpp index 64efb93f7d4ea50913c7876bbeb5831eb4c0fa99..b75f31cb1c6fa0143de9622f13e2fe81316c294b 100644 --- a/emper/io.hpp +++ b/emper/io.hpp @@ -370,7 +370,7 @@ inline auto writevAndWait(int fildes, const struct iovec *iov, int iovcnt) -> ss * * @return fd on success, -1 on error */ -inline auto openatAndWait(int dirfd, const char *pathname, int flags, mode_t mode = 0) -> size_t { +inline auto openatAndWait(int dirfd, const char *pathname, int flags, mode_t mode = 0) -> int { OpenatFuture future(dirfd, pathname, flags, mode); future.submit(); return future.waitAndSetErrno(); @@ -407,7 +407,7 @@ inline auto openatAndWait(int dirfd, const char *pathname, int flags, mode_t mod * * @return fd on success, -1 on error */ -inline auto openAndWait(const char *pathname, int flags, mode_t mode = 0) -> size_t { +inline auto openAndWait(const char *pathname, int flags, mode_t mode = 0) -> int { OpenatFuture future(AT_FDCWD, pathname, flags, mode); future.submit(); return future.waitAndSetErrno(); @@ -439,7 +439,7 @@ inline auto openAndWait(const char *pathname, int flags, mode_t mode = 0) -> siz * * @return 0 on success, -1 on error */ -inline auto closeAndWait(int fd) -> ssize_t { +inline auto closeAndWait(int fd) -> int { CloseFuture future(fd); future.submit(); return future.waitAndSetErrno(); diff --git a/emper/io/Future.cpp b/emper/io/Future.cpp index 013997e48ab062918c6ee6572da931c850f92de8..f6767182e3b977a06ef3122b86f590c9ef820c25 100644 --- a/emper/io/Future.cpp +++ b/emper/io/Future.cpp @@ -2,8 +2,6 @@ // Copyright © 2020-2021 Florian Fischer #include "Future.hpp" -#include <sys/types.h> // for ssize_t - #include <cassert> // for assert #include <cerrno> // for errno, EAGAIN, EWOULDBLOCK #include <ostream> // for operator<<, ostream, basic_ost... @@ -58,7 +56,7 @@ auto Future::wait() -> int32_t { return returnValue; } -auto Future::waitAndSetErrno() -> ssize_t { +auto Future::waitAndSetErrno() -> int32_t { int32_t res = wait(); // move error codes from io_uring into errno if (res < 0) { diff --git a/emper/io/Future.hpp b/emper/io/Future.hpp index 09e4128acd47478a65eb328310e2a9b518a2eedf..06f9b45609f8354606a7f4c493f379e1cc56daaf 100644 --- a/emper/io/Future.hpp +++ b/emper/io/Future.hpp @@ -4,7 +4,7 @@ #include <liburing.h> // for io_uring_prep_read, io_uring_p... #include <sys/socket.h> // for socklen_t -#include <sys/types.h> // for ssize_t +#include <sys/types.h> #include <cassert> #include <cstddef> // for size_t @@ -82,7 +82,10 @@ class Future : public Logger<LogSubsystem::IO> { const int fd; void* const buf; const size_t len; - const int offsetOrFlags; + union { + const off_t offset; + const int flags; + }; /** * Return value of the operation. @@ -142,8 +145,11 @@ class Future : public Logger<LogSubsystem::IO> { void recordCompletionInternal(Stats& stats, int32_t res) const; - Future(Operation op, int fd, void* buf, size_t len, int offsetOrFlags) - : op(op), fd(fd), buf(buf), len(len), offsetOrFlags(offsetOrFlags){}; + Future(Operation op, int fd, void* buf, size_t len, off_t offset) + : op(op), fd(fd), buf(buf), len(len), offset(offset){}; + + Future(Operation op, int fd, void* buf, size_t len, int flags) + : op(op), fd(fd), buf(buf), len(len), flags(flags){}; public: // Clang-tidy warns about the exception possibly thrown by @@ -270,7 +276,7 @@ class Future : public Logger<LogSubsystem::IO> { * * @return -1 on error and errno will be set, otherwise the return value of the IO request */ - auto waitAndSetErrno() -> ssize_t; + auto waitAndSetErrno() -> int32_t; /** * @brief Equivalent to calling wait() after calling submit() @@ -326,21 +332,28 @@ class PartialCompletableFuture : public Future { * When the IO request returns to the user the combination of @c future.returnValue and * @c future.partialCompletion can signal partial completion. */ - ssize_t partialCompletion; + int32_t partialCompletion; // return immediately to the user - static const ssize_t DISABLE_PARTIAL_COMPLETION = -1; + static const int32_t DISABLE_PARTIAL_COMPLETION = -1; // try to fully complete the request - static const ssize_t ENABLE_PARTIAL_COMPLETION = 0; + static const int32_t ENABLE_PARTIAL_COMPLETION = 0; - PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, int offsetOrFlags, + PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, off_t offset, + bool completeFully) + : Future(op, fd, buf, len, offset), + partialCompletion(completeFully ? ENABLE_PARTIAL_COMPLETION : DISABLE_PARTIAL_COMPLETION){}; + PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, int flags, bool completeFully) - : Future(op, fd, buf, len, offsetOrFlags), + : Future(op, fd, buf, len, flags), partialCompletion(completeFully ? ENABLE_PARTIAL_COMPLETION : DISABLE_PARTIAL_COMPLETION){}; - PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, int offsetOrFlags, - ssize_t partialCompletion) - : Future(op, fd, buf, len, offsetOrFlags), partialCompletion(partialCompletion){}; + PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, off_t offset, + int32_t partialCompletion) + : Future(op, fd, buf, len, offset), partialCompletion(partialCompletion){}; + PartialCompletableFuture(Operation op, int fd, void* buf, size_t len, int flags, + int32_t partialCompletion) + : Future(op, fd, buf, len, flags), partialCompletion(partialCompletion){}; /** * Used for Stats::recordCompletion double dispatch @@ -414,7 +427,7 @@ class PartialCompletableFuture : public Future { * * @return return the result received from the io_uring */ - auto wait(ssize_t& partialCompletion) -> int32_t { + auto wait(int32_t& partialCompletion) -> int32_t { int32_t res = Future::wait(); partialCompletion = this->partialCompletion; return res; @@ -424,7 +437,7 @@ class PartialCompletableFuture : public Future { /* * @brief Equivalent to calling wait(partialCompletion) after calling submit() */ - inline auto submitAndWait(ssize_t& partialCompletion) -> int32_t { + inline auto submitAndWait(int32_t& partialCompletion) -> int32_t { Future::submit(); return wait(partialCompletion); } @@ -445,15 +458,14 @@ class PartialCompletableFuture : public Future { class SendFuture : public PartialCompletableFuture { void prepareSqe(io_uring_sqe* sqe) override { if (partialCompletion == DISABLE_PARTIAL_COMPLETION) { - io_uring_prep_send(sqe, fd, buf, len, offsetOrFlags); + io_uring_prep_send(sqe, fd, buf, len, flags); } else { - io_uring_prep_send(sqe, fd, (char*)buf + partialCompletion, len - partialCompletion, - offsetOrFlags); + io_uring_prep_send(sqe, fd, (char*)buf + partialCompletion, len - partialCompletion, flags); } } public: - SendFuture(int socket, const void* buffer, size_t length, int flags, ssize_t partialCompletion) + SendFuture(int socket, const void* buffer, size_t length, int flags, int32_t partialCompletion) : PartialCompletableFuture(Operation::SEND, socket, const_cast<void*>(buffer), length, flags, partialCompletion){}; @@ -463,9 +475,7 @@ class SendFuture : public PartialCompletableFuture { }; class RecvFuture : public Future { - void prepareSqe(io_uring_sqe* sqe) override { - io_uring_prep_recv(sqe, fd, buf, len, offsetOrFlags); - } + void prepareSqe(io_uring_sqe* sqe) override { io_uring_prep_recv(sqe, fd, buf, len, flags); } public: RecvFuture(int socket, void* buffer, size_t length, int flags) @@ -484,6 +494,7 @@ class ConnectFuture : public Future { class AcceptFuture : public Future { void prepareSqe(io_uring_sqe* sqe) override { + // NOLINTNEXTLINE(performance-no-int-to-ptr) io_uring_prep_accept(sqe, fd, (struct sockaddr*)buf, (socklen_t*)len, 0); } @@ -495,15 +506,15 @@ class AcceptFuture : public Future { class ReadFuture : public PartialCompletableFuture { void prepareSqe(io_uring_sqe* sqe) override { if (partialCompletion == DISABLE_PARTIAL_COMPLETION) { - io_uring_prep_read(sqe, fd, buf, len, offsetOrFlags); + io_uring_prep_read(sqe, fd, buf, len, offset); } else { io_uring_prep_read(sqe, fd, (char*)buf + partialCompletion, len - partialCompletion, - offsetOrFlags + partialCompletion); + offset + partialCompletion); } } public: - ReadFuture(int fildes, void* buf, size_t nbyte, int offset, bool read_all = false) + ReadFuture(int fildes, void* buf, size_t nbyte, off_t offset, bool read_all = false) : PartialCompletableFuture( Operation::READ, fildes, buf, nbyte, offset, read_all ? ENABLE_PARTIAL_COMPLETION : DISABLE_PARTIAL_COMPLETION){}; @@ -511,28 +522,30 @@ class ReadFuture : public PartialCompletableFuture { class OpenatFuture : public Future { void prepareSqe(io_uring_sqe* sqe) override { - io_uring_prep_openat(sqe, fd, reinterpret_cast<const char*>(buf), len, offsetOrFlags); + io_uring_prep_openat(sqe, fd, reinterpret_cast<const char*>(buf), static_cast<int>(len), + static_cast<mode_t>(offset)); } public: OpenatFuture(int dirfd, const void* pathname, int flags, mode_t mode = 0) - : Future(Operation::OPENAT, dirfd, const_cast<void*>(pathname), flags, mode){}; + : Future(Operation::OPENAT, dirfd, const_cast<void*>(pathname), flags, + static_cast<off_t>(mode)){}; }; class WriteFuture : public PartialCompletableFuture { void prepareSqe(io_uring_sqe* sqe) override { if (partialCompletion == DISABLE_PARTIAL_COMPLETION) { - io_uring_prep_write(sqe, fd, buf, len, offsetOrFlags); + io_uring_prep_write(sqe, fd, buf, len, offset); } else { // TODO: think about partial writes with incremental offset! // Are transparent incremental writes on files without O_APPEND even reasonable? io_uring_prep_write(sqe, fd, (char*)buf + partialCompletion, len - partialCompletion, - offsetOrFlags + partialCompletion); + offset + partialCompletion); } } public: - WriteFuture(int fildes, const void* buf, size_t nbyte, int offset, bool write_all = true) + WriteFuture(int fildes, const void* buf, size_t nbyte, off_t offset, bool write_all = true) : PartialCompletableFuture( Operation::WRITE, fildes, const_cast<void*>(buf), nbyte, offset, write_all ? ENABLE_PARTIAL_COMPLETION : DISABLE_PARTIAL_COMPLETION){}; diff --git a/emper/io/GlobalIoContext.cpp b/emper/io/GlobalIoContext.cpp index da8c944d7d1ecc18cecbf498a0ab226a3d81091e..e7bb9982a6c574a8c14d7b185e53cdf21a524682 100644 --- a/emper/io/GlobalIoContext.cpp +++ b/emper/io/GlobalIoContext.cpp @@ -123,7 +123,7 @@ auto GlobalIoContext::globalCompleterFunc(void* arg) -> void* { case PointerTags::Future: { auto* future = tptr.getPtr<Future>(); - uint32_t res = cqe->res; + int32_t res = cqe->res; future->recordCompletion(globalIoContext->stats, res); future->completeFromAnywhere(res); @@ -152,7 +152,7 @@ void GlobalIoContext::startGlobalCompleter() { void GlobalIoContext::initiateTermination() { uint64_t write_buf = 1; - int bytes_written = write(notificationEventFd, &write_buf, sizeof(write_buf)); + ssize_t bytes_written = write(notificationEventFd, &write_buf, sizeof(write_buf)); if (bytes_written != sizeof(write_buf)) { DIE_MSG_ERRNO("Writing to globalIo termination eventfd failed"); } diff --git a/emper/lib/TaggedPtr.hpp b/emper/lib/TaggedPtr.hpp index fcbeb1d3721b3593e273616755fa9cc86e1a9eb7..532082c20730df4a9a2cd8b7a4ad985013f33a4e 100644 --- a/emper/lib/TaggedPtr.hpp +++ b/emper/lib/TaggedPtr.hpp @@ -41,6 +41,7 @@ class TaggedPtr { template <typename T> [[nodiscard]] inline auto getPtr() const -> T* { // ignore the least significant bit of the tagged pointer + // NOLINTNEXTLINE(performance-no-int-to-ptr) return reinterpret_cast<T*>(tptr & (TPTR_POINTER_MASK - 1)); } @@ -91,6 +92,7 @@ class TaggedPtr { inline operator uintptr_t() const { return tptr; } + // NOLINTNEXTLINE(performance-no-int-to-ptr) inline operator void*() const { return reinterpret_cast<void*>(tptr); } inline operator bool() const { return tptr != 0; } diff --git a/tests/io/SimpleDiskAndNetworkTest.cpp b/tests/io/SimpleDiskAndNetworkTest.cpp index 182bcdbfce52463de6d2850aaa299f87e51131e6..919c2bf72325f1f9b4a8065e9277a6036ad90370 100644 --- a/tests/io/SimpleDiskAndNetworkTest.cpp +++ b/tests/io/SimpleDiskAndNetworkTest.cpp @@ -26,9 +26,8 @@ static void server_func(int sockfd) { struct sockaddr_in clientaddr; socklen_t clientaddr_len = sizeof(clientaddr); - auto client_fd = - emper::io::accept(sockfd, reinterpret_cast<struct sockaddr*>(&clientaddr), &clientaddr_len) - ->wait(); + auto client_fd = emper::io::acceptAndWait(sockfd, reinterpret_cast<struct sockaddr*>(&clientaddr), + &clientaddr_len); if (client_fd < 0) { DIE_MSG_ERRNO("accept failed"); @@ -40,7 +39,7 @@ static void server_func(int sockfd) { char read_buf[MAX]; for (;;) { - int received = emper::io::recv(client_fd, recv_buf, sizeof(recv_buf), 0)->wait(); + ssize_t received = emper::io::recvAndWait(client_fd, recv_buf, sizeof(recv_buf), 0); if (received == 0) { exit(EXIT_SUCCESS); } @@ -57,7 +56,7 @@ static void server_func(int sockfd) { DIE_MSG_ERRNO("mkstemp failed"); } - int written = emper::io::writeFile(file_fd, recv_buf, received)->wait(); + ssize_t written = emper::io::writeFileAndWait(file_fd, recv_buf, received); if (written < 0) { DIE_MSG_ERRNO("write failed"); } @@ -68,7 +67,7 @@ static void server_func(int sockfd) { DIE_MSG_ERRNO("open failed"); } - int bytes_read = emper::io::readFile(file_fd, read_buf, written)->wait(); + ssize_t bytes_read = emper::io::readFileAndWait(file_fd, read_buf, written); if (bytes_read == 0) { DIE_MSG("nothing to read"); } @@ -78,7 +77,7 @@ static void server_func(int sockfd) { } close(file_fd); - int sent = emper::io::send(client_fd, read_buf, bytes_read, 0)->wait(); + ssize_t sent = emper::io::sendAndWait(client_fd, read_buf, bytes_read, 0); if (sent == 0) { DIE_MSG("client socket unexpected shutdown"); } @@ -107,7 +106,7 @@ static void server_func(int sockfd) { iov[1].iov_len = s2.length(); auto writevFuture = emper::io::writev(file_fd, &iov[0], iovcnt); - written = writevFuture->wait(); + written = writevFuture->waitAndSetErrno(); if (written < 0) { DIE_MSG_ERRNO("wrtev failed"); } @@ -119,7 +118,7 @@ static void server_func(int sockfd) { } auto readFuture = emper::io::readFile(file_fd, read_buf, written, 0, true); - bytes_read = readFuture->wait(); + bytes_read = readFuture->waitAndSetErrno(); if (bytes_read == 0) { DIE_MSG("nothing to read"); }