The Pedigree Project 0.1
TerminationDeferral.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/process/TerminationDeferral.h"
10#include "pedigree/kernel/process/Thread.h"
11#include "pedigree/kernel/processor/Processor.h"
12#include "pedigree/kernel/processor/ProcessorInformation.h"
13
14namespace {
15#if PEDIGREE_AFFINITY_TESTS
16void reportIdentityFailure(Thread* expected, Thread* observed, Thread* stable, const void* scope,
17 const char* site, const void* caller, bool interrupts) {
18 ERROR_NOLOCK("AFFINITY-IDENTITY: expected=" << Hex << expected << " observed=" << observed);
19 ERROR_NOLOCK("AFFINITY-IDENTITY: stable=" << Hex << stable << " scope=" << scope);
20 ERROR_NOLOCK("AFFINITY-IDENTITY: site=" << site << " caller=" << Hex << caller);
21 ERROR_NOLOCK("AFFINITY-IDENTITY: cpu=" << Dec << Processor::index() << " irq=" << interrupts);
22}
23#endif
24
25#if PEDIGREE_AFFINITY_TESTS
26__attribute__((noinline))
27#endif
28void assertCurrentThread(Thread* thread, const void* scope, const char* site) {
29 Thread* observed = thread ? Processor::information().getCurrentThread() : nullptr;
30 if (thread && observed != thread) {
31#if PEDIGREE_AFFINITY_TESTS
32 const bool interrupts = Processor::getInterrupts();
34 Thread* stable = Processor::information().getCurrentThread();
35 reportIdentityFailure(thread, observed, stable, scope, site, __builtin_return_address(0),
36 interrupts);
37#else
38 (void)scope;
39 (void)site;
40#endif
41 FATAL("TerminationDeferral moved or released on a different Thread.");
42 }
43}
44} // namespace
45
46void TerminationDeferral::initialise(bool active) {
47 m_pThread = active ? Processor::information().getCurrentThread() : nullptr;
48#if PEDIGREE_AFFINITY_TESTS
49 if (active) {
50 const bool interrupts = Processor::getInterrupts();
52 Thread* stable = Processor::information().getCurrentThread();
53 if (m_pThread != stable) {
54 reportIdentityFailure(m_pThread, m_pThread, stable, this, "construct",
55 __builtin_return_address(0), interrupts);
56 FATAL("TerminationDeferral captured a different Thread.");
57 }
58 Processor::setInterrupts(interrupts);
59 }
60#endif
61 if (m_pThread) {
62 m_pThread->registerFreshTerminationDeferral(m_Record);
63 } else {
64 m_Record = DeferredScopeRecord();
65 }
66}
67
68TerminationDeferral::TerminationDeferral(TerminationDeferral&& other) noexcept
69 : m_pThread(other.m_pThread), m_Record() {
70 assertCurrentThread(m_pThread, this, "move-construct");
71 if (m_pThread) {
72 m_pThread->moveTerminationDeferral(other.m_Record, m_Record);
73 }
74 other.m_pThread = nullptr;
75}
76
77TerminationDeferral::~TerminationDeferral() {
78 if (m_pThread) {
79 assertCurrentThread(m_pThread, this, "destroy");
80 m_pThread->unregisterTerminationDeferral(m_Record);
81 }
82}
83
84TerminationDeferral& TerminationDeferral::operator=(TerminationDeferral&& other) noexcept {
85 if (this != &other) {
86 if (m_pThread && other.m_pThread) {
87 assertCurrentThread(m_pThread, this, "replace-destination");
88 assertCurrentThread(other.m_pThread, &other, "replace-source");
89 if (m_pThread != other.m_pThread) {
90 FATAL("TerminationDeferral replaced from a different Thread.");
91 }
92
93 // Both objects already protect this Thread. Keep the destination's
94 // lexical record and retire the source's pure termination record. Pure
95 // deferrals can be reset before a newer lexical scope, unlike cleanup
96 // and event records whose release remains strictly LIFO.
97 m_pThread->unregisterTerminationDeferral(other.m_Record);
98 other.m_pThread = nullptr;
99 return *this;
100 }
101
102 if (m_pThread) {
103 assertCurrentThread(m_pThread, this, "reset-destination");
104 m_pThread->unregisterTerminationDeferral(m_Record);
105 }
106 assertCurrentThread(other.m_pThread, &other, "adopt-source");
107 m_pThread = other.m_pThread;
108 if (m_pThread) {
109 m_pThread->moveTerminationDeferral(other.m_Record, m_Record);
110 }
111 other.m_pThread = nullptr;
112 }
113 return *this;
114}
static bool getInterrupts()
static ProcessorInformation & information()
static void setInterrupts(bool bEnable)
static size_t index()
@ Dec
Definition Log.h:144
@ Hex
Definition Log.h:142