9#include "pedigree/kernel/Atomic.h"
10#include "pedigree/kernel/Log.h"
11#include "pedigree/kernel/errors.h"
12#include "pedigree/kernel/process/Process.h"
13#include "pedigree/kernel/process/Scheduler.h"
14#include "pedigree/kernel/process/Thread.h"
15#include "pedigree/kernel/processor/Processor.h"
20#include "modules/subsys/posix/FileDescriptor.h"
21#include "modules/subsys/posix/PosixSubsystem.h"
22#include "modules/subsys/posix/eventfd-syscalls.h"
23#include "modules/subsys/posix/file-syscalls.h"
24#include "modules/subsys/posix/poll-syscalls.h"
28constexpr size_t HostedAttempts = 10000;
30struct EventFdCloseContext {
31 explicit EventFdCloseContext(
int fd)
32 : fd(fd), entered(0), returned(0), result(-2), error(0), value(0) {}
42int blockOnEventFd(
void* parameter) {
43 EventFdCloseContext* context =
reinterpret_cast<EventFdCloseContext*
>(parameter);
45 context->entered += 1;
48 posix_read(context->fd,
reinterpret_cast<char*
>(&context->value),
sizeof(context->value));
50 context->returned += 1;
54struct EventFdRegressionContext {
55 EventFdRegressionContext() : passed(false), returned(0) {}
61int exerciseEventFd(
void* parameter) {
62 EventFdRegressionContext* context =
reinterpret_cast<EventFdRegressionContext*
>(parameter);
67 const int invalidFlags = posix_eventfd2(0, 0x40000000);
68 passed &= invalidFlags == -1 && thread->
getErrno() == Error::InvalidArgument;
70 const int fd = posix_eventfd2(0, LinuxEventFd::NonBlock | LinuxEventFd::CloseOnExec);
72 passed &= fd >= 0 && acquireDescriptor(fd, descriptor) && descriptor->
getFlags() == FD_CLOEXEC &&
77 char shortBuffer[
sizeof(uint64_t) - 1] = {};
80 const int shortRead = posix_read(fd, shortBuffer,
sizeof(shortBuffer));
81 passed &= shortRead == -1 && thread->
getErrno() == Error::InvalidArgument;
83 const int emptyRead = posix_read(fd,
reinterpret_cast<char*
>(&value),
sizeof(value));
84 passed &= emptyRead == -1 && thread->
getErrno() == Error::NoMoreProcesses;
86 const int shortWrite = posix_write(fd, shortBuffer,
sizeof(shortBuffer),
false);
87 passed &= shortWrite == -1 && thread->
getErrno() == Error::InvalidArgument;
88 value = ~static_cast<uint64_t>(0);
90 const int invalidWrite = posix_write(fd,
reinterpret_cast<char*
>(&value),
sizeof(value),
false);
91 passed &= invalidWrite == -1 && thread->
getErrno() == Error::InvalidArgument;
94 const int initialWrite = posix_write(fd,
reinterpret_cast<char*
>(&value),
sizeof(value),
false);
95 struct pollfd pollState = {fd, POLLIN | POLLOUT, 0};
96 const int pollResult = posix_poll_safe(&pollState, 1, 0);
97 uint64_t longRead[2] = {};
98 const int accumulatedRead = posix_read(fd,
reinterpret_cast<char*
>(longRead),
sizeof(longRead));
99 passed &= initialWrite == 8 && pollResult == 1 &&
100 (pollState.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT) &&
101 accumulatedRead == 8 && longRead[0] == 2 && longRead[1] == 0;
103 uint64_t longWrite[2] = {3, 5};
105 const int longWriteResult =
106 posix_write(fd,
reinterpret_cast<char*
>(longWrite),
sizeof(longWrite),
false);
107 passed &= longWriteResult == -1 && thread->
getErrno() == Error::InvalidArgument;
109 uint64_t vectorWriteValue = 7;
110 struct iovec writeVectors[2] = {
111 {&vectorWriteValue, 3},
112 {
reinterpret_cast<uint8_t*
>(&vectorWriteValue) + 3, 5},
115 const int splitVectorWrite = posix_writev(fd, writeVectors, 2);
116 const int splitVectorError = thread->
getErrno();
118 uint64_t vectorWriteValues[2] = {7, 9};
119 struct iovec completeWriteVectors[2] = {
120 {&vectorWriteValues[0],
sizeof(vectorWriteValues[0])},
121 {&vectorWriteValues[1],
sizeof(vectorWriteValues[1])},
123 const int vectorWrite = posix_writev(fd, completeWriteVectors, 2);
124 uint64_t vectorReadValue = 0;
125 struct iovec readVectors[2] = {
126 {&vectorReadValue, 2},
127 {
reinterpret_cast<uint8_t*
>(&vectorReadValue) + 2, 6},
129 const int vectorRead = posix_readv(fd, readVectors, 2);
130 passed &= splitVectorWrite == -1 && splitVectorError == Error::InvalidArgument &&
131 vectorWrite == 16 && vectorRead == 8 && vectorReadValue == 16;
133 const int alias = posix_dup(fd);
134 const int originalClose = posix_close(fd);
136 const int aliasWrite = posix_write(alias,
reinterpret_cast<char*
>(&value),
sizeof(value),
false);
138 const int aliasRead = posix_read(alias,
reinterpret_cast<char*
>(&value),
sizeof(value));
139 passed &= alias >= 0 && originalClose == 0 && aliasWrite == 8 && aliasRead == 8 && value == 4;
141 value = ~static_cast<uint64_t>(0) - 1;
142 const int maximumWrite =
143 posix_write(alias,
reinterpret_cast<char*
>(&value),
sizeof(value),
false);
144 pollState = {alias, POLLIN | POLLOUT, 0};
145 const int maximumPoll = posix_poll_safe(&pollState, 1, 0);
148 const int overflowWrite =
149 posix_write(alias,
reinterpret_cast<char*
>(&value),
sizeof(value),
false);
150 const int overflowError = thread->
getErrno();
152 const int maximumRead = posix_read(alias,
reinterpret_cast<char*
>(&value),
sizeof(value));
153 passed &= maximumWrite == 8 && maximumPoll == 1 && (pollState.revents & POLLIN) &&
154 !(pollState.revents & POLLOUT) && overflowWrite == -1 &&
155 overflowError == Error::NoMoreProcesses && maximumRead == 8 &&
156 value == ~static_cast<uint64_t>(0) - 1 && posix_close(alias) == 0;
158 const int semaphoreFd = posix_eventfd2(2, LinuxEventFd::Semaphore | LinuxEventFd::NonBlock);
159 uint64_t firstSemaphore = 0;
160 uint64_t secondSemaphore = 0;
161 const int firstSemaphoreRead =
162 posix_read(semaphoreFd,
reinterpret_cast<char*
>(&firstSemaphore),
sizeof(firstSemaphore));
163 const int secondSemaphoreRead =
164 posix_read(semaphoreFd,
reinterpret_cast<char*
>(&secondSemaphore),
sizeof(secondSemaphore));
166 const int emptySemaphoreRead =
167 posix_read(semaphoreFd,
reinterpret_cast<char*
>(&value),
sizeof(value));
168 const int emptySemaphoreError = thread->
getErrno();
169 passed &= semaphoreFd >= 0 && firstSemaphoreRead == 8 && secondSemaphoreRead == 8 &&
170 firstSemaphore == 1 && secondSemaphore == 1 && emptySemaphoreRead == -1 &&
171 emptySemaphoreError == Error::NoMoreProcesses && posix_close(semaphoreFd) == 0;
173 const int blockingFd = posix_eventfd(0);
176 if (blockingFd >= 0 && acquireDescriptor(blockingFd, blockingDescriptor)) {
179 blockingDescriptor.reset();
180 EventFdCloseContext closeContext(blockingFd);
182 new Thread(thread->
getParent(), blockOnEventFd, &closeContext,
nullptr,
false,
true,
true);
183 reader->setName(
"hosted eventfd close waiter");
184 const bool readerStarted =
reader->start();
185 bool readerBlocked =
false;
186 for (
size_t attempt = 0; attempt < HostedAttempts && readerStarted; ++attempt) {
188 if (closeContext.entered &&
reader->getWaitDebugInfo(info) && info.queue && info.queued &&
189 reader->getStatus() == Thread::Sleeping) {
190 readerBlocked =
true;
195 const int blockingClose = readerBlocked ? posix_close(blockingFd) : -1;
196 for (
size_t attempt = 0; attempt < 256 && !closeContext.returned; ++attempt) {
199 const bool remainedBlocked = !closeContext.returned;
200 const int retainedWrite =
201 retainedEventFd && remainedBlocked ? retainedEventFd->writeValue(1,
false) : -1;
202 const bool readerJoined = readerStarted &&
reader->joinForCompletion();
203 if (!readerStarted) {
206 passed &= blockingFd >= 0 && readerStarted && readerBlocked && blockingClose == 0 &&
207 remainedBlocked && retainedWrite == 8 && readerJoined && closeContext.returned == 1 &&
208 closeContext.result == 8 && closeContext.error == 0 && closeContext.value == 1;
210 context->passed = passed;
211 context->returned += 1;
212 return passed ? 0 : 1;
216bool runHostedEventFdRegressions(
Process* kernelProcess) {
219 EventFdRegressionContext context;
220 Thread*
worker =
new Thread(process, exerciseEventFd, &context,
nullptr,
false,
true,
true);
221 worker->setName(
"hosted eventfd regression worker");
222 const bool started =
worker->start();
223 const bool joined = started &&
worker->joinForCompletion();
228 const bool passed = started && joined && context.returned == 1 && context.passed;
232 "HOSTED-SYSCALL-TEST: FAIL eventfd-counter-readiness-lifetime: "
233 "flags, counter, vector I/O, polling, alias, or in-flight close semantics failed");
237 NOTICE(
"HOSTED-SYSCALL-TEST: PASS eventfd-counter-readiness-lifetime");
SharedPointer< EventFd > getEventFdImpl() const
int getFlags() const
Get current descriptor flags.
int getStatusFlags() const
Get current status flags.
static ProcessorInformation & information()
static Scheduler & instance()
void setErrno(size_t err)
Process * getParent() const