2#include "pedigree/kernel/Atomic.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/process/Scheduler.h"
5#include "pedigree/kernel/process/Semaphore.h"
6#include "pedigree/kernel/process/Thread.h"
7#include "pedigree/kernel/utilities/RequestQueue.h"
9#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS && THREADS
13 Queue() :
RequestQueue(MakeConstantString(
"paging completion fixture")), entered(0), release(0) {}
23 uint64_t
executeRequest(uint64_t hold, uint64_t token, uint64_t, uint64_t, uint64_t, uint64_t,
24 uint64_t, uint64_t)
override {
38 (request.p2 && waitForPreallocated(*
reinterpret_cast<PreallocatedRequest*
>(request.p2))))
47 static int run(
void* opaque) {
48 auto& self = *
static_cast<Wait*
>(opaque);
49 self.result = self.queue.waitForPreallocated(self.token);
60 static void released(
void* opaque) {
61 auto& self = *
static_cast<ReleaseGate*
>(opaque);
62 if (self.queue.canWaitForCompletion() || self.queue.waitForPreallocated(*self.token))
64 self.entered.release();
66 if (!self.release.acquireForCompletion(1, 10))
70bool queued(
Thread* thread) {
71 for (
size_t attempts = 0; attempts < 10000; ++attempts) {
82 static int run(
void* opaque) {
83 auto& self = *
static_cast<Destroy*
>(opaque);
95bool runHostedPagingRequestRegressions() {
96 using Result = RequestQueue::PreallocatedPublishResult;
100 ReleaseGate release{queue};
102 release.token = &token;
104 passed &= queue.publishPreallocated(token, 0, 1,
reinterpret_cast<uintptr_t
>(&token)) ==
106 const bool entered = queue.entered.acquireForCompletion(1, 10);
107 Wait
waiter{queue, token};
109 const bool beforeCompletion = queued(thread) && !
waiter.done.tryAcquire();
110 queue.release.release();
112 const bool duringRelease = !token.isAvailable() && !
waiter.done.tryAcquire();
114 const bool completed =
waiter.done.acquireForCompletion(1, 10);
115 passed &= entered && beforeCompletion && releasing && duringRelease && completed;
117 passed &= queue.waitForPreallocated(token);
118 passed &= !queue.failures && !release.failures;
126 passed &= queue.publishPreallocated(blocker, 0, 1,
reinterpret_cast<uintptr_t
>(&blocker)) ==
128 passed &= queue.entered.acquireForCompletion(1, 10);
129 passed &= queue.publishPreallocated(cancelled, 0, 0,
reinterpret_cast<uintptr_t
>(&cancelled)) ==
131 Wait
waiter{queue, cancelled};
133 passed &= queued(waiting);
134 Destroy destroy{queue};
136 for (
size_t attempts = 0;
137 attempts < 10000 && queue.getLifecycleState() != RequestQueue::LifecycleState::Stopping;
140 passed &= queue.getLifecycleState() == RequestQueue::LifecycleState::Stopping;
141 queue.release.release();
142 passed &= destroy.done.acquireForCompletion(1, 10) &&
waiter.done.acquireForCompletion(1, 10);
144 passed &=
waiter.result && cancelled.isAvailable() && blocker.isAvailable();
145 passed &= queue.cancellations == 1 && !queue.failures;
148 NOTICE(
"HOSTED-STORAGE-PAGING: PASS request-completion-retirement");
150 ERROR(
"HOSTED-STORAGE-PAGING: FAIL request-completion-retirement");
MUST_USE_RESULT bool waitForPreallocated(PreallocatedRequest &request)
bool canWaitForCompletion()
virtual void cancelRequest(const Request &request)
virtual uint64_t executeRequest(uint64_t p1, uint64_t p2, uint64_t p3, uint64_t p4, uint64_t p5, uint64_t p6, uint64_t p7, uint64_t p8)=0
static Scheduler & instance()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
bool getWaitDebugInfo(WaitDebugInfo &info)
int(* ThreadStartFunc)(void *)