// SPDX-License-Identifier: LGPL-3.0-or-later // Copyright © 2020-2021 Florian Fischer #include <fcntl.h> #include <sys/eventfd.h> // for eventfd #include <sys/types.h> // for ssize_t #include <array> #include <cassert> // for assert #include <cerrno> // for EBADF, ECANCELED #include <cstdint> // for uint64_t, int32_t #include <cstdlib> // for exit, EXIT_SUCCESS #include "Common.hpp" // for DIE_MSG_ERRNO, DIE_MSG #include "io.hpp" #include "io/Future.hpp" // for ReadFuture, CloseFuture, WriteFuture using emper::io::CloseFuture; using emper::io::ReadFuture; using emper::io::WriteFuture; static void successChain() { int efd = eventfd(0, 0); if (efd == -1) { DIE_MSG_ERRNO("eventfd failed"); } uint64_t write_buf = 42; WriteFuture writeFuture(efd, &write_buf, sizeof(write_buf), 0); uint64_t read_buf; ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); readFuture.setDependency(writeFuture); CloseFuture closeFuture(efd); closeFuture.setDependency(readFuture); ssize_t res = closeFuture.submitAndWait(); if (res == -1) { DIE_MSG_ERRNO("linked requests chain failed"); } if (read_buf != 42) { DIE_MSG("dependent read value differs from written value"); } } static void successLoop() { int efd = eventfd(0, 0); if (efd == -1) { DIE_MSG_ERRNO("eventfd failed"); } const unsigned ITERATIONS = 10000; for (unsigned i = 0; i < ITERATIONS; ++i) { uint64_t write_buf = 42; WriteFuture writeFuture(efd, &write_buf, sizeof(write_buf), 0); uint64_t read_buf; ReadFuture readFuture(efd, &read_buf, sizeof(read_buf), 0); readFuture.setDependency(writeFuture); ssize_t res = readFuture.submitAndWait(); if (res == -1) { DIE_MSG_ERRNO("linked requests chain failed"); } if (read_buf != 42) { DIE_MSG("dependent read value differs from written value"); } } CloseFuture closeFuture(efd); ssize_t res = closeFuture.submitAndWait(); if (res == -1) { DIE_MSG_ERRNO("linked requests chain failed"); } } static void failureChainInvCor() { std::array<char, 32> buf; ReadFuture invalidReadFuture(-1, buf.data(), buf.size(), 0); ReadFuture readFuture(0, buf.data(), buf.size(), 0); readFuture.setDependency(invalidReadFuture); int32_t res = readFuture.submitAndWait(); assert(res == -ECANCELED); res = invalidReadFuture.wait(); assert(res == -EBADF); } static void failureChainCorInvCor() { std::array<char, 32> buf; int fd = emper::io::openAndWait("/dev/null", O_WRONLY); // int fd = open("/dev/null", O_WRONLY, 0); assert(fd != -1); WriteFuture correctFuture1(fd, buf.data(), buf.size(), 0); ReadFuture invalidFuture(-1, buf.data(), buf.size(), 0); invalidFuture.setDependency(correctFuture1); WriteFuture correctFuture2(fd, buf.data(), buf.size(), 0); correctFuture2.setDependency(invalidFuture); int32_t res = correctFuture2.submitAndWait(); assert(res == -ECANCELED); res = invalidFuture.wait(); assert(res == -EBADF); res = correctFuture1.wait(); assert(res == (int32_t)buf.size()); emper::io::closeAndWait(fd); } void emperTest() { // This leaves the io_uring in a weird state because the successChain() afterwards // fails because the write future is already completed with -ECANCELED but // there is successful cqe in the CQ for this future failureChainCorInvCor(); successChain(); successLoop(); failureChainInvCor(); // failureChainInvCor left the io_uring in a weird state because // the io_uring_submit of the openAndWait() never returns. // failureChainCorInvCor(); exit(EXIT_SUCCESS); }