8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/errors.h"
11#include "pedigree/kernel/process/Process.h"
12#include "pedigree/kernel/process/Scheduler.h"
13#include "pedigree/kernel/process/SignalEvent.h"
14#include "pedigree/kernel/process/Thread.h"
15#include "pedigree/kernel/processor/Processor.h"
16#include "pedigree/kernel/time/Time.h"
21#include "modules/subsys/posix/PosixProcess.h"
22#include "modules/subsys/posix/PosixSubsystem.h"
23#include "modules/subsys/posix/system-syscalls.h"
24#include <sys/resource.h>
28constexpr int PreservedErrno = 173;
29constexpr int TestUid = 913;
30constexpr size_t TestSignal = 10;
32struct PriorityContext {
39int priorityWorker(
void* parameter) {
40 PriorityContext* context =
reinterpret_cast<PriorityContext*
>(parameter);
42 const int processId =
static_cast<int>(context->process->getId());
45 constexpr bool Abis[] = {
false,
true};
46 constexpr int Selectors[] = {PRIO_PROCESS, PRIO_PGRP, PRIO_USER};
47 for (
bool linuxAbi : Abis) {
48 const int expected = linuxAbi ? 20 : 0;
49 for (
int selector : Selectors) {
50 const int explicitTarget = selector == PRIO_USER ? TestUid : processId;
52 passed &= posix_getpriority(selector, 0, linuxAbi) == expected &&
53 current->
getErrno() == PreservedErrno;
55 passed &= posix_getpriority(selector, explicitTarget, linuxAbi) == expected &&
56 current->
getErrno() == PreservedErrno;
58 passed &= posix_getpriority(selector, INT_MAX, linuxAbi) == -1 &&
60 (selector == PRIO_PROCESS ? Error::NoSuchProcess : Error::Unimplemented);
62 passed &= posix_getpriority(selector, -1, linuxAbi) == -1 &&
63 current->
getErrno() == Error::NoSuchProcess;
67 passed &= posix_getpriority(PRIO_PROCESS, context->foreignPid, linuxAbi) == expected &&
68 current->
getErrno() == PreservedErrno;
70 passed &= posix_getpriority(PRIO_PGRP, context->foreignPid, linuxAbi) == -1 &&
71 current->
getErrno() == Error::Unimplemented;
73 passed &= posix_getpriority(PRIO_USER, TestUid + 1, linuxAbi) == -1 &&
74 current->
getErrno() == Error::Unimplemented;
77 posix_getpriority(-1, 0, linuxAbi) == -1 && current->
getErrno() == Error::InvalidArgument;
80 posix_getpriority(3, 0, linuxAbi) == -1 && current->
getErrno() == Error::InvalidArgument;
83 context->passed = passed;
84 context->returned += 1;
85 return passed ? 0 : 1;
88bool priorityQueries(
Process* kernelProcess) {
91 process->setUserId(TestUid);
96 foreign->setUserId(TestUid + 1);
98 PriorityContext context{process,
static_cast<int>(foreign->
getId())};
99 Thread*
worker =
new Thread(process, priorityWorker, &context,
nullptr,
false,
true,
true);
100 worker->setName(
"hosted getpriority query contracts");
101 const bool started =
worker->start();
102 const bool joined = started &&
worker->joinForCompletion();
106 const bool passed = started && joined && context.returned == 1 && context.passed;
110 NOTICE(
"HOSTED-SYSCALL-TEST: PASS getpriority-query-contracts");
112 ERROR(
"HOSTED-SYSCALL-TEST: FAIL getpriority-query-contracts");
117void unusedSignalHandler(
size_t) {}
122 :
SignalEvent(reinterpret_cast<uintptr_t>(&unusedSignalHandler), TestSignal, ~0UL, 0, true,
134 bool collisionQueued =
false;
138WaitContext* g_WaitCollision =
nullptr;
142 WaitContext* context = g_WaitCollision;
143 if (!context || debugState != Thread::ProcessWait ||
144 thread->
getParent() != context->child->getParent()) {
147 WaitQueue::setBeforeBlockHook(
nullptr);
148 context->collisionQueued = thread->
sendEvent(context->signal);
149 context->child->suspend(SIGSTOP);
152int interruptedWaitWorker(
void* parameter) {
153 WaitContext* context =
reinterpret_cast<WaitContext*
>(parameter);
155 const int childPid =
static_cast<int>(context->child->getId());
156 current->setInterruptionReason(Thread::InterruptedBySignal);
158 const int result = posix_waitpid(childPid,
nullptr, WUNTRACED,
nullptr);
159 bool passed = result == -1 && current->
getErrno() == Error::Interrupted &&
160 current->getInterruptionReason() == Thread::NotInterrupted &&
163 current->clearInterruption();
167 passed &= posix_waitpid(childPid,
nullptr, WNOHANG | WUNTRACED,
nullptr) == 0 &&
168 current->
getErrno() == PreservedErrno;
170 g_WaitCollision = context;
171 WaitQueue::setBeforeBlockHook(&childStatusSignalCollision);
173 const int childStatus = posix_waitpid(childPid,
nullptr, WUNTRACED,
nullptr);
174 WaitQueue::setBeforeBlockHook(
nullptr);
175 g_WaitCollision =
nullptr;
176 passed &= childStatus == childPid && current->
getErrno() == PreservedErrno &&
177 context->collisionQueued && current->
hasEvent(context->signal) &&
178 current->getInterruptionReason() == Thread::NotInterrupted;
180 passed &= posix_waitpid(childPid,
nullptr, WNOHANG | WUNTRACED,
nullptr) == 0 &&
181 current->getInterruptionReason() == Thread::NotInterrupted;
184 context->passed = passed;
185 context->returned += 1;
186 return passed ? 0 : 1;
189bool waitUntilBlocked(
Thread* thread) {
190 const Time::Timestamp deadline = Time::getTicks() + 2 * Time::Multiplier::Second;
191 while (Time::getTicks() < deadline) {
193 uintptr_t debugAddress = 0;
195 thread->
getDebugState(debugAddress) == Thread::ProcessWait) {
204 const Time::Timestamp deadline = Time::getTicks() + 2 * Time::Multiplier::Second;
205 while (!returned && Time::getTicks() < deadline) {
208 return returned == 1;
211bool caughtSignalWait(
Process* kernelProcess) {
219 DeferredWaitSignal signal;
220 WaitContext context{child, &signal};
221 Thread*
worker =
new Thread(process, interruptedWaitWorker, &context,
nullptr,
false,
true,
true);
222 worker->setName(
"hosted caught-signal waitpid interruption");
223 const bool started =
worker->start();
224 const bool queued = started && waitUntilBlocked(
worker) &&
worker->sendEvent(&signal);
225 const bool returnedBeforeChildStatus = queued && waitForReturn(context.returned);
226 if (started && !returnedBeforeChildStatus) {
230 const bool joined = started &&
worker->joinForCompletion();
235 const bool passed = queued && returnedBeforeChildStatus && joined && context.passed;
239 NOTICE(
"HOSTED-SYSCALL-TEST: PASS waitpid-caught-signal-interruption");
241 ERROR(
"HOSTED-SYSCALL-TEST: FAIL waitpid-caught-signal-interruption");
247bool runHostedProcessQueryRegressions(
Process* kernelProcess) {
248 const bool priorityPassed = priorityQueries(kernelProcess);
249 const bool waitPassed = caughtSignalWait(kernelProcess);
250 return priorityPassed && waitPassed;
virtual bool requiresExactUserReturnState() const
void suspend(int stopSignal=0)
static ProcessorInformation & information()
static Scheduler & instance()
void setErrno(size_t err)
bool getWaitDebugInfo(WaitDebugInfo &info)
bool hasEvent(Event *pEvent)
void cullEvent(Event *pEvent)
DebugState getDebugState(uintptr_t &address)
Process * getParent() const
bool sendEvent(Event *pEvent)