3#if PEDIGREE_UTS_NAMESPACE_TESTS && THREADS
4#include "pedigree/kernel/Log.h"
5#include "pedigree/kernel/process/Process.h"
6#include "pedigree/kernel/process/Scheduler.h"
7#include "pedigree/kernel/process/Semaphore.h"
8#include "pedigree/kernel/process/Thread.h"
9#include "pedigree/kernel/processor/Processor.h"
10#include "pedigree/kernel/processor/ProcessorInformation.h"
12#include "modules/subsys/posix/PosixProcess.h"
13#include "modules/subsys/posix/PosixSubsystem.h"
14#include "modules/subsys/posix/uts-namespace.h"
17bool check(
bool condition,
const char* detail) {
19 ERROR(
"UTS-NAMESPACE-TEST: FAIL " << detail);
23int forbiddenEntry(
void* parameter) {
24 *
static_cast<bool*
>(parameter) =
true;
29 const size_t references = source.
refcount();
31 if (!check(posix_uts_prepare_thread(source,
false, prepared) == UtsStatus::Success,
32 "terminal preparation"))
35 Thread* peer =
new Thread(&process, forbiddenEntry, &entered,
nullptr,
false,
true,
true);
36 if (!check(peer !=
nullptr,
"terminal thread allocation"))
42 context.publishThread(prepared, *peer,
false);
45 bool passed = check(
bool(prepared) && !context.acquireThread(*peer, absent) &&
46 !context.taskTarget(taskId, target),
47 "terminal publication consumed or exposed a binding");
49 passed &= check(source.
refcount() == references,
"rejected preparation retained namespace");
51 FATAL(
"UTS-NAMESPACE-TEST: terminal thread could not be joined safely");
52 passed &= check(!entered,
"terminal thread executed its entry point");
54 NOTICE(
"UTS-NAMESPACE-TEST: PASS terminal publication rollback");
60 bool released =
false;
63int controlledEntry(
void* parameter) {
64 auto& state = *
static_cast<PeerState*
>(parameter);
66 state.released = state.release.acquire(1, 10);
72 if (!check(posix_uts_prepare_thread(source,
false, prepared) == UtsStatus::Success,
76 Thread* peer =
new Thread(&process, controlledEntry, &state,
nullptr,
false,
true,
true);
77 if (!check(peer !=
nullptr,
"live thread allocation"))
80 context.publishThread(prepared, *peer,
false);
81 const bool started = peer->
start();
82 const bool ready = started && state.ready.acquire(1, 10);
85 bool passed = check(ready && !prepared && context.taskTarget(taskId, retained) &&
86 posix_uts_acquire_target(retained, captured) == UtsStatus::Success &&
87 captured->identity() == source->identity(),
88 "live task namespace capture");
89 state.release.release();
93 FATAL(
"UTS-NAMESPACE-TEST: controlled thread could not be joined safely");
96 passed &= check(state.released && !context.taskTarget(taskId, absent) &&
97 posix_uts_acquire_target(retained, missing) == UtsStatus::Missing &&
98 !missing && captured && captured->identity() == source->identity(),
99 "retained target survived task retirement or lost namespace ownership");
101 NOTICE(
"UTS-NAMESPACE-TEST: PASS retained task retirement");
105int coordinator(
void* parameter) {
106 bool& passed = *
static_cast<bool*
>(parameter);
109 auto context =
static_cast<PosixSubsystem*
>(process->getSubsystem())->namespaceContext();
111 if (!check(context && context->acquireThread(current, source),
"coordinator binding"))
113 passed = terminalPublication(*context, *process, source) &&
114 targetRetirement(*context, *process, source);
116 passed &= check(context->leaderTarget(leader),
"leader capture before close");
121 passed &= check(!context->acquireThread(current, absent) && !context->leaderTarget(noLeader) &&
122 posix_uts_acquire_target(leader, absent) == UtsStatus::Missing && !absent,
123 "closed context retained a live binding");
125 NOTICE(
"UTS-NAMESPACE-TEST: PASS closed context");
130bool utsNamespaceRegression() {
131 NOTICE(
"UTS-NAMESPACE-TEST: BEGIN");
133 if (!check(process !=
nullptr,
"isolated process allocation"))
138 return check(
false,
"isolated subsystem allocation");
140 process->setSubsystem(subsystem);
141 auto context = subsystem->namespaceContext();
144 if (!check(context && context->valid() && posix_uts_initial(initial) == UtsStatus::Success &&
145 posix_uts_copy(initial, source) == UtsStatus::Success &&
146 posix_uts_prepare_thread(source,
false, prepared) == UtsStatus::Success,
147 "isolated namespace preparation")) {
152 Thread*
worker =
new Thread(process, coordinator, &passed,
nullptr,
false,
true,
true);
155 return check(
false,
"coordinator allocation");
157 context->publishThread(prepared, *
worker,
true);
159 const bool started =
worker->start();
162 const bool joined =
worker->joinForCompletion();
164 FATAL(
"UTS-NAMESPACE-TEST: coordinator could not be joined safely");
166 passed = check(started && joined && passed,
"isolated coordinator") && passed;
168 NOTICE(
"UTS-NAMESPACE-TEST: END PASS");
static ProcessorInformation & information()
static Scheduler & instance()
void setUnwindState(UnwindType ut)
@ TerminateThread
Exit only this thread during Process exit.
Process * getParent() const