2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/Scheduler.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/utilities/assert.h"
6#include "pedigree/kernel/utilities/utility.h"
8#include "PosixSubsystem.h"
9#include "trace-context.h"
12size_t localId(
const Thread& thread) {
13 return const_cast<Thread&
>(thread).getId();
23 task.m_Token->m_ParentDeathCreator =
creator;
24 task.m_ParentDeathNext = s_Tasks;
26 s_Tasks->m_ParentDeathPrevious = &task;
36 const bool armed = signal && task->m_ParentDeathCreator && task->m_ParentDeathCreator->live();
37 if (armed != task->m_ParentDeathArmed) {
44 task->m_ParentDeathArmed = armed;
45 __atomic_store_n(&task->m_ParentDeathSignal, signal, __ATOMIC_RELEASE);
58 if (node.m_ParentDeathPrevious) {
59 node.m_ParentDeathPrevious->m_ParentDeathNext = node.m_ParentDeathNext;
61 s_Tasks = node.m_ParentDeathNext;
63 if (node.m_ParentDeathNext) {
64 node.m_ParentDeathNext->m_ParentDeathPrevious = node.m_ParentDeathPrevious;
66 node.m_ParentDeathNext = node.m_ParentDeathPrevious =
nullptr;
67 if (task->m_ParentDeathArmed) {
68 task->m_ParentDeathArmed =
false;
75 for (
auto* child = s_Tasks; child; child = child->m_ParentDeathNext) {
76 if (child->m_Token->m_ParentDeathCreator != task || !child->m_Token->m_ParentDeathArmed) {
79 child->m_Token->m_ParentDeathArmed =
false;
81 const int signal = child->m_Token->parentDeathSignal();
85 deliveries.
pushBack({child->m_Token, signal});
89 for (
const auto& delivery : deliveries) {
91 if (posix_trace_acquire_task(delivery.task, target) != TraceStatus::Success) {
95 subsystem->
sendSignal(target.get(), delivery.signal,
false,
true);
102 static size_t s_ArmedCount;
104Mutex ParentDeathSignals::s_Lock;
106size_t ParentDeathSignals::s_ArmedCount = 0;
113bool TraceTaskToken::live()
const {
114 return snapshot().state == State::Live;
117void TraceTaskToken::publish(
const Thread& thread) {
119 assert(m_Identity.state == State::Staged);
121 m_Identity.localThreadId = localId(thread);
122 m_Identity.linuxTaskId = thread.getTaskId();
123 m_Identity.state = State::Live;
126void TraceTaskToken::promote(
const Thread& thread) {
128 if (m_Identity.state != State::Live)
131 assert(m_Identity.localThreadId == localId(thread));
132 m_Identity.linuxTaskId = thread.getTaskId();
135void TraceTaskToken::close() {
137 m_Identity.state = State::Closed;
140PosixTraceContext::~PosixTraceContext() {
143 assert(!m_ThreadCreations && !m_EnrollmentPending);
146bool PosixTraceContext::valid()
const {
147 return !__atomic_load_n(&m_Closed, __ATOMIC_ACQUIRE);
150void PosixTraceContext::attach(
Process& process) {
153 assert(!m_Attached || m_ProcessId == process.
getId());
154 m_ProcessId = process.
getId();
162 if (!m_Attached || !valid())
163 return TraceStatus::Missing;
167 return TraceStatus::NoMemory;
169 if (!prepared.get()->m_Token)
170 return TraceStatus::NoMemory;
171 result = pedigree_std::move(prepared);
172 return TraceStatus::Success;
177 assert(prepared && prepared.get()->m_Token);
179 if (!m_Attached || !valid() || thread.
getParent()->
getId() != m_ProcessId ||
181 return TraceStatus::Missing;
184 if (tokenUnlocked(localId(thread)))
185 return TraceStatus::Denied;
186 prepared.get()->m_Token->publish(thread);
187 ParentDeathSignals::publish(*prepared.get(), m_Creator);
189 node->m_Next = m_Tasks;
191 return TraceStatus::Success;
194TraceTaskRef PosixTraceContext::tokenUnlocked(
size_t id)
const {
195 for (
auto* task = m_Tasks; task; task = task->m_Next) {
196 const auto identity = task->m_Token->snapshot();
197 if (
identity.state == TraceTaskToken::State::Live &&
identity.localThreadId ==
id)
198 return task->m_Token;
203bool PosixTraceContext::ownsTokenUnlocked(
const TraceTaskRef& token)
const {
204 for (
auto* task = m_Tasks; task; task = task->m_Next) {
205 if (task->m_Token == token)
206 return token->live();
216 if (!m_Attached || !valid() || thread.
getParent()->
getId() != m_ProcessId)
218 acquired = tokenUnlocked(localId(thread));
220 result = pedigree_std::move(acquired);
224void PosixTraceContext::setCreator(
const TraceTaskRef& token) {
226 assert(m_Attached && valid() && !m_Tasks && !m_Creator);
235bool PosixTraceContext::setParentDeathSignal(
const Thread& thread,
int signal) {
237 if (!taskToken(thread, task)) {
240 return ParentDeathSignals::arm(task, signal);
243void PosixTraceContext::promoteExec(
const Thread& thread) {
250 token = tokenUnlocked(localId(thread));
252 token->promote(thread);
265bool PosixTraceContext::selectStop(
size_t parentPid,
bool stopped,
bool continued,
bool consume,
268 if (!valid() || !m_Incoming)
270 const auto owner = m_Incoming->tracer()->snapshot();
271 return owner.state == TraceTaskToken::State::Live && owner.processId == parentPid &&
272 m_Incoming->selectStop(stopped, continued, consume, report);
275bool PosixTraceContext::hasIncoming()
const {
277 return bool(m_Incoming);
284 if (m_Incoming.
get() == relation)
285 retired = pedigree_std::move(m_Incoming);
289void PosixTraceContext::retireTask(
const Thread& thread) {
298 auto** position = &m_Tasks;
299 while (*position && (*position)->m_Token->snapshot().localThreadId != localId(thread))
300 position = &(*position)->m_Next;
304 *position = retired->m_Next;
305 retired->m_Token->close();
307 if (m_Incoming && m_Incoming->tracee() == retired->m_Token)
308 incoming = pedigree_std::move(m_Incoming);
310 ParentDeathSignals::retire(*retired);
312 incoming->taskClosed(retired->m_Token);
314 OwnedRelation* outgoing =
nullptr;
317 auto** position = &m_Outgoing;
318 while (*position && (*position)->relation->tracer() != retired->m_Token)
319 position = &(*position)->next;
321 outgoing = *position;
322 *position = outgoing->next;
327 outgoing->relation->taskClosed(retired->m_Token);
333void PosixTraceContext::close() {
339 OwnedRelation* outgoing =
nullptr;
346 __atomic_store_n(&m_Closed,
true, __ATOMIC_RELEASE);
349 outgoing = m_Outgoing;
350 m_Outgoing =
nullptr;
351 for (
auto* task = tasks; task; task = task->m_Next)
352 task->m_Token->close();
353 creator = pedigree_std::move(m_Creator);
355 incoming = pedigree_std::move(m_Incoming);
358 incoming->taskClosed(incoming->tracee());
360 auto* next = outgoing->next;
361 outgoing->relation->taskClosed(outgoing->relation->tracer());
366 auto* next = tasks->m_Next;
367 ParentDeathSignals::retire(*tasks);
376 return TraceStatus::Missing;
377 const auto identity = token->snapshot();
378 if (
identity.state != TraceTaskToken::State::Live)
379 return TraceStatus::Missing;
382 process->getType() != Process::Posix)
383 return TraceStatus::Missing;
387 return TraceStatus::Missing;
388 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
390 if (!subsystem || !subsystem->traceContext().taskToken(*task.get(), actual) || actual != token ||
392 return TraceStatus::Missing;
393 result = pedigree_std::move(task);
394 return TraceStatus::Success;
virtual void sendSignal(Thread *pThread, int signal, bool yield=true, bool processDirected=false)
MUST_USE_RESULT bool acquireThreadById(ThreadLease &lease, size_t id)
static Scheduler & instance()
static SharedPointer< TraceTaskToken > tryAllocate(Args...)
@ Continue
No unwind necessary, carry on as normal.
@ TerminateThread
Exit only this thread during Process exit.
UnwindType getUnwindState()
Process * getParent() const
T * releaseOwnership() noexcept
A vector / dynamic array.
void pushBack(const T &value)