The Pedigree Project 0.1
trace-admission.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/Thread.h"
4#include "pedigree/kernel/utilities/assert.h"
5
6#include "trace-context.h"
7
8TraceCloneAdmission::~TraceCloneAdmission() {
9 if (m_Context)
10 m_Context->finishThreadCreation();
11}
12
13TraceEnrollmentAdmission::~TraceEnrollmentAdmission() {
14 if (m_Context)
15 m_Context->cancelEnrollment();
16}
17
18TraceStatus PosixTraceContext::reserveThreadCreation(TraceCloneAdmission& admission) {
19 assert(!admission.m_Context);
20 LockGuard<Mutex> guard(m_AdmissionLock);
21 if (!m_Attached || !valid())
22 return TraceStatus::Missing;
23 if (m_EnrollmentPending || hasIncoming() || m_ThreadCreations == ~size_t(0))
24 return TraceStatus::Busy;
25 ++m_ThreadCreations;
26 admission.m_Context = this;
27 return TraceStatus::Success;
28}
29
30void PosixTraceContext::finishThreadCreation() {
31 LockGuard<Mutex> guard(m_AdmissionLock);
32 assert(m_ThreadCreations);
33 --m_ThreadCreations;
34}
35
36TraceStatus PosixTraceContext::reserveEnrollment(Thread& thread,
37 TraceEnrollmentAdmission& admission) {
38 assert(!admission.m_Context && !admission.m_Tracer && !admission.m_Tracee);
39 LockGuard<Mutex> guard(m_AdmissionLock);
40 if (!m_Attached || !valid() || thread.getParent()->getId() != m_ProcessId ||
42 return TraceStatus::Missing;
43 if (m_EnrollmentPending || m_ThreadCreations)
44 return TraceStatus::Busy;
45 if (hasIncoming())
46 return TraceStatus::Denied;
47 if (thread.getTaskId() != m_ProcessId || thread.getParent()->getNumThreads() != 1)
48 return TraceStatus::Unsupported;
49 TraceTaskRef tracee = tokenUnlocked(thread.getId());
50 if (!tracee || !m_Creator || !m_Creator->live())
51 return TraceStatus::Missing;
52 admission.m_Tracer = m_Creator;
53 admission.m_Tracee = tracee;
54 admission.m_Context = this;
55 m_EnrollmentPending = true;
56 return TraceStatus::Success;
57}
58
59void PosixTraceContext::cancelEnrollment() {
60 LockGuard<Mutex> guard(m_AdmissionLock);
61 assert(m_EnrollmentPending);
62 m_EnrollmentPending = false;
63}
64
65TraceStatus PosixTraceContext::commitEnrollment(TraceEnrollmentAdmission& admission,
66 const TraceRelationRef& relation) {
67 assert(admission.m_Context == this);
68 if (!relation || !relation->valid() || relation->tracer() != admission.m_Tracer ||
69 relation->tracee() != admission.m_Tracee)
70 return TraceStatus::Denied;
71 LockGuard<Mutex> guard(m_AdmissionLock);
72 assert(m_EnrollmentPending);
73 if (!valid() || !ownsTokenUnlocked(admission.m_Tracee) || !admission.m_Tracer->live())
74 return TraceStatus::Missing;
75 assert(!m_ThreadCreations);
76 LockGuard<Spinlock> publication(m_RelationLock);
77 if (m_Incoming)
78 return TraceStatus::Denied;
79 // taskClosed serializes with activate in the relation's short state guard.
80 // Any closure callbacks run after that guard and after this publication.
81 if (!relation->activate())
82 return TraceStatus::Missing;
83 m_Incoming = relation;
84 m_EnrollmentPending = false;
85 admission.m_Context = nullptr;
86 return TraceStatus::Success;
87}
88
89TraceStatus PosixTraceContext::registerTracee(const TraceTaskRef& tracer,
90 const TraceRelationRef& relation) {
91 if (!tracer || !relation || !relation->valid() || relation->tracer() != tracer)
92 return TraceStatus::Denied;
94 if (!entry)
95 return TraceStatus::NoMemory;
96 entry.get()->relation = relation;
97 LockGuard<Mutex> guard(m_AdmissionLock);
98 if (!m_Attached || !valid() || !ownsTokenUnlocked(tracer))
99 return TraceStatus::Missing;
100 for (auto* existing = m_Outgoing; existing; existing = existing->next) {
101 if (existing->relation == relation)
102 return TraceStatus::Success;
103 }
104 entry.get()->next = m_Outgoing;
105 m_Outgoing = entry.releaseOwnership();
106 return TraceStatus::Success;
107}
108
109void PosixTraceContext::unregisterTracee(const PosixTraceRelation* relation) {
110 if (!valid())
111 return;
112 OwnedRelation* retired = nullptr;
113 {
114 LockGuard<Mutex> guard(m_AdmissionLock);
115 auto** position = &m_Outgoing;
116 while (*position && (*position)->relation.get() != relation)
117 position = &(*position)->next;
118 if (*position) {
119 retired = *position;
120 *position = retired->next;
121 }
122 }
123 delete retired;
124}
size_t getId()
Definition Process.h:462
size_t getNumThreads()
Definition Process.cc:1271
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:500
UnwindType getUnwindState()
Definition Thread.h:518
Process * getParent() const
Definition Thread.h:325
size_t getId()
Definition Thread.h:450
size_t getTaskId() const
Definition Thread.h:455
#define assert(x)
Definition assert.h:39