2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/Process.h"
4#include "pedigree/kernel/process/Scheduler.h"
5#include "pedigree/kernel/process/Thread.h"
6#include "pedigree/kernel/processor/Processor.h"
7#include "pedigree/kernel/processor/ProcessorInformation.h"
8#include "pedigree/kernel/syscallError.h"
9#include "pedigree/kernel/utilities/assert.h"
10#include "pedigree/kernel/utilities/utility.h"
12#include "PosixProcess.h"
13#include "PosixSubsystem.h"
15#include "uts-namespace.h"
20size_t namespaceCount = 1;
21uint64_t nextIdentity = 1;
22constexpr size_t MaximumNamespaces = 256;
23size_t localId(
const Thread& thread) {
24 return const_cast<Thread&
>(thread).getId();
32 size_t localId = 0, taskId = 0;
40 bool attached =
false, closed =
false;
45PosixUtsNamespace::PosixUtsNamespace(uint64_t
identity,
const Snapshot& names,
bool charged,
47 : m_Owner(owner), m_Identity(
identity), m_Charged(charged), m_Names(names) {}
48PosixUtsNamespace::~PosixUtsNamespace() {
50 __atomic_sub_fetch(&namespaceCount,
size_t(1), __ATOMIC_RELEASE);
56void PosixUtsNamespace::setName(
bool domain,
const char* bytes,
size_t length) {
59 char* output = domain ? m_Names.domain : m_Names.node;
61 MemoryCopy(output, bytes, length);
62 ByteSet(output + length, 0, 65 - length);
65UtsStatus posix_uts_initial(
UtsRef& result) {
69 if (!initialNamespace) {
71 MemoryCopy(names.node,
"pedigree", 8);
72 MemoryCopy(names.domain,
"(none)", 6);
74 if (!initialNamespace)
75 return UtsStatus::NoMemory;
77 acquired = initialNamespace;
79 result = pedigree_std::move(acquired);
80 return UtsStatus::Success;
85 return UtsStatus::Missing;
86 const auto names = source->snapshot();
90 if (__atomic_load_n(&namespaceCount, __ATOMIC_ACQUIRE) >= MaximumNamespaces ||
91 nextIdentity == ~uint64_t(0))
92 return UtsStatus::NoSpace;
93 __atomic_add_fetch(&namespaceCount,
size_t(1), __ATOMIC_ACQ_REL);
98 __atomic_sub_fetch(&namespaceCount,
size_t(1), __ATOMIC_RELEASE);
99 return UtsStatus::NoMemory;
101 result = pedigree_std::move(copy);
102 return UtsStatus::Success;
105PreparedUtsThread::PreparedUtsThread() =
default;
106PreparedUtsThread::~PreparedUtsThread() =
default;
107UtsStatus posix_uts_prepare_thread(
const UtsRef& source,
bool copy,
111 return UtsStatus::Missing;
114 const auto status = posix_uts_copy(source, space, owner);
115 if (status != UtsStatus::Success)
120 return UtsStatus::NoMemory;
122 if (!prepared.get()->m_Binding)
123 return UtsStatus::NoMemory;
124 result = pedigree_std::move(prepared);
125 return UtsStatus::Success;
128PosixUtsTarget::PosixUtsTarget() =
default;
131PosixUtsTarget::~PosixUtsTarget() =
default;
132PosixUtsTarget::operator bool()
const {
136PosixNamespaceContext::PosixNamespaceContext()
138PosixNamespaceContext::~PosixNamespaceContext() {
141bool PosixNamespaceContext::valid()
const {
144void PosixNamespaceContext::attach(
Process& process) {
148 assert(!m_View->closed && (!m_View->attached || m_View->processId == process.
getId()));
149 m_View->processId = process.
getId();
150 m_View->attached =
true;
153bool PosixNamespaceContext::acquireThread(
const Thread& thread,
UtsRef& result)
const {
159 if (m_View->closed || !m_View->attached || thread.
getParent()->
getId() != m_View->processId)
161 for (
auto* node = m_View->first; node; node = node->m_Next) {
162 if (node->m_Binding->localId == localId(thread) && node->m_Binding->live) {
163 acquired = node->m_Binding->space;
170 result = pedigree_std::move(acquired);
175 Thread& thread,
bool leader) {
176 assert(m_View && prepared && prepared.get()->m_Binding);
180 assert(m_View->attached && !m_View->closed && thread.
getParent()->
getId() == m_View->processId);
185 for (
auto* node = m_View->first; node; node = node->m_Next)
186 assert(node->m_Binding->localId != localId(thread));
187 prepared.get()->m_Binding->localId = localId(thread);
188 prepared.get()->m_Binding->taskId = thread.getTaskId();
189 prepared.get()->m_Binding->live =
true;
190 prepared.get()->m_Next = m_View->first;
192 oldLeader = pedigree_std::move(m_View->leader);
193 m_View->leader = prepared.get()->m_Binding;
199void PosixNamespaceContext::promoteExec(
const Thread& thread) {
200 assert(
bool(m_View));
203 for (
auto* node = m_View->first; node; node = node->m_Next) {
204 if (node->m_Binding->localId == localId(thread) && node->m_Binding->live) {
205 node->m_Binding->taskId = thread.getTaskId();
206 oldLeader = pedigree_std::move(m_View->leader);
207 m_View->leader = node->m_Binding;
214UtsStatus PosixNamespaceContext::replaceThread(
const Thread& thread,
const UtsRef& replacement) {
215 if (!m_View || !replacement)
216 return UtsStatus::Missing;
220 return UtsStatus::Missing;
221 for (
auto* node = m_View->first; node; node = node->m_Next) {
222 if (node->m_Binding->localId == localId(thread) && node->m_Binding->live) {
223 previous = pedigree_std::move(node->m_Binding->space);
224 node->m_Binding->space = replacement;
225 return UtsStatus::Success;
228 return UtsStatus::Missing;
231void PosixNamespaceContext::retireThread(
const Thread& thread) {
232 if (!m_View || __atomic_load_n(&m_View->closed, __ATOMIC_ACQUIRE))
239 auto** link = &m_View->first;
241 if ((*link)->m_Binding->localId == localId(thread)) {
243 *link = retired->m_Next;
244 retired->m_Next =
nullptr;
245 retired->m_Binding->live =
false;
246 previous = pedigree_std::move(retired->m_Binding->space);
247 if (m_View->leader == retired->m_Binding)
248 oldLeader = pedigree_std::move(m_View->leader);
251 link = &(*link)->m_Next;
257void PosixNamespaceContext::close() {
258 if (!m_View || __atomic_load_n(&m_View->closed, __ATOMIC_ACQUIRE))
264 __atomic_store_n(&m_View->closed,
true, __ATOMIC_RELEASE);
265 retired = m_View->first;
266 m_View->first =
nullptr;
267 oldLeader = pedigree_std::move(m_View->leader);
268 for (
auto* node = retired; node; node = node->m_Next)
269 node->m_Binding->live =
false;
272 auto* next = retired->m_Next;
273 retired->m_Binding->space.
reset();
279bool PosixNamespaceContext::leaderTarget(
PosixUtsTarget& result)
const {
285 if (m_View->closed || !m_View->attached)
287 target.m_View = m_View;
293bool PosixNamespaceContext::taskTarget(
size_t taskId,
PosixUtsTarget& result)
const {
299 if (m_View->closed || !m_View->attached)
301 for (
auto* node = m_View->first; node; node = node->m_Next) {
302 if (node->m_Binding->live && node->m_Binding->taskId == taskId) {
303 target.m_View = m_View;
304 target.m_Task = node->m_Binding;
305 target.m_ExpectedTaskId = taskId;
317 return taskTarget(thread.getTaskId(), result);
320bool PosixNamespaceContext::nextTaskTarget(
size_t afterTaskId,
size_t& taskId,
327 if (m_View->closed || !m_View->attached)
329 for (
auto* node = m_View->first; node; node = node->m_Next) {
330 const size_t id = node->m_Binding->taskId;
331 if (node->m_Binding->live &&
id > afterTaskId &&
332 (!target.m_Task ||
id < target.m_ExpectedTaskId)) {
333 target.m_View = m_View;
334 target.m_Task = node->m_Binding;
335 target.m_ExpectedTaskId = id;
341 taskId = target.m_ExpectedTaskId;
348 return UtsStatus::Missing;
352 return UtsStatus::Missing;
353 if (lease->getType() != Process::Posix || current->
getParent()->getType() != Process::Posix)
354 return UtsStatus::Denied;
360 auto* subsystem =
static_cast<PosixSubsystem*
>(lease->getSubsystem());
363 if (!context || context->m_View != target.m_View)
364 return UtsStatus::Missing;
365 if (current->
getParent() != lease.get()) {
367 const auto destination =
static_cast<PosixProcess*
>(lease.get())->snapshotCredentials();
368 if (!Process::currentFilesystemCredentials(source) || !destination.dumpable ||
369 source.uid != destination.ruid || source.uid != destination.euid ||
370 source.uid != destination.suid || source.gid != destination.rgid ||
371 source.gid != destination.egid || source.gid != destination.sgid)
372 return UtsStatus::Denied;
375 auto binding = target.m_Task ? target.m_Task : target.m_View->leader;
376 if (target.m_View->closed || !binding || !binding->live ||
377 (target.m_Task && binding->taskId != target.m_ExpectedTaskId))
378 return UtsStatus::Missing;
379 acquired = binding->space;
382 return UtsStatus::Missing;
383 result = pedigree_std::move(acquired);
384 return UtsStatus::Success;
387int posix_uts_error(UtsStatus status) {
389 case UtsStatus::Success:
392 case UtsStatus::NoMemory:
393 SYSCALL_ERROR(OutOfMemory);
395 case UtsStatus::NoSpace:
396 SYSCALL_ERROR(NoSpaceLeftOnDevice);
398 case UtsStatus::Missing:
399 SYSCALL_ERROR(DoesNotExist);
401 case UtsStatus::Denied:
402 SYSCALL_ERROR(PermissionDenied);
404 case UtsStatus::Invalid:
405 SYSCALL_ERROR(InvalidArgument);
Memory-mapped file interface.
static MemoryMapManager & instance()
static ProcessorInformation & information()
static Scheduler & instance()
static SharedPointer< T > tryAllocate(Args...)
@ TerminateThread
Exit only this thread during Process exit.
UnwindType getUnwindState()
Process * getParent() const
T * releaseOwnership() noexcept