Newer
Older
// 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 <cassert> // for assert
#include <cerrno> // for EBADF, ECANCELED
#include <cstdint> // for uint64_t, int32_t
#include "Common.hpp" // for DIE_MSG_ERRNO, DIE_MSG
#include "Debug.hpp"
#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");
}
}
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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;
// GCC 11.1.0 reports that buf is not initialized.
// Which is totally fine because we read into it.
IGNORE_MAYBE_UNINITIALIZED
ReadFuture invalidReadFuture(-1, buf.data(), buf.size(), 0);
POP_DIAGNOSTIC
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();

Florian Fischer
committed
// Since the kernel commit cf10960426515 io_uring does not
// submit broken links and completes any request before a
// invalid one as canceled.
assert(res == -ECANCELED || res == (int32_t)buf.size());
emper::io::closeAndWait(fd);
void emperTest() {
// Test if a invalid chain leaves the IoContext in an unexpected / invalid state
failureChainCorInvCor();
successChain();
successLoop();
failureChainInvCor();