The Pedigree Project 0.1
OperationBarrier.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/panic.h"
10#include "pedigree/kernel/process/OperationBarrier.h"
11#include "pedigree/kernel/process/TerminationDeferral.h"
12#include "pedigree/kernel/process/Thread.h"
13
14OperationBarrier::Lease::Lease() : m_Barrier(nullptr) {}
15
16OperationBarrier::Lease::Lease(OperationBarrier* barrier) : m_Barrier(barrier) {}
17
18OperationBarrier::Lease::Lease(Lease&& other) noexcept : m_Barrier(other.m_Barrier) {
19 other.m_Barrier = nullptr;
20}
21
22OperationBarrier::Lease::~Lease() {
23 reset();
24}
25
26OperationBarrier::Lease& OperationBarrier::Lease::operator=(
27 OperationBarrier::Lease&& other) noexcept {
28 if (this != &other) {
29 reset();
30 m_Barrier = other.m_Barrier;
31 other.m_Barrier = nullptr;
32 }
33 return *this;
34}
35
36void OperationBarrier::Lease::reset() {
37 if (m_Barrier) {
38 OperationBarrier* barrier = m_Barrier;
39 m_Barrier = nullptr;
40 barrier->leave();
41 }
42}
43
44OperationBarrier::OperationBarrier() : m_Waiters(), m_State(0) {}
45
46OperationBarrier::~OperationBarrier() {
47 auto guard = m_Waiters.acquire();
48 if (__atomic_load_n(&m_State, __ATOMIC_ACQUIRE) != Closed) {
49 panic("OperationBarrier destroyed before close-and-drain completed.");
50 }
51}
52
54 size_t state = __atomic_load_n(&m_State, __ATOMIC_RELAXED);
55 do {
56 if (state & Closed) {
57 return false;
58 }
59 if (state == CountMask) {
60 panic("OperationBarrier operation count overflow.");
61 }
62 } while (!__atomic_compare_exchange_n(&m_State, &state, state + 1, true, __ATOMIC_ACQUIRE,
63 __ATOMIC_RELAXED));
64 return true;
65}
66
68 if (!tryEnter()) {
69 lease = Lease();
70 return false;
71 }
72
73 lease = Lease(this);
74 return true;
75}
76
78 size_t state = __atomic_load_n(&m_State, __ATOMIC_RELAXED);
79 do {
80 if (!(state & CountMask)) {
81 panic("OperationBarrier operation count underflow.");
82 }
83 if (state == (Closed | 1)) {
84 // Publish the final closed release under the queue lock, so a drainer
85 // cannot destroy the barrier while we still have to wake its waiters.
86 auto guard = m_Waiters.acquire();
87 __atomic_fetch_sub(&m_State, size_t{1}, __ATOMIC_ACQ_REL);
88 guard.wakeAll(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(this));
89 return;
90 }
91 } while (!__atomic_compare_exchange_n(&m_State, &state, state - 1, true, __ATOMIC_RELEASE,
92 __ATOMIC_RELAXED));
93 // A concurrent close can now drain and destroy us; do not touch the barrier.
94}
95
97 __atomic_fetch_or(&m_State, Closed, __ATOMIC_ACQ_REL);
98}
99
101 auto guard = m_Waiters.acquire();
102 size_t state = 0;
103 return __atomic_compare_exchange_n(&m_State, &state, Closed, false, __ATOMIC_ACQ_REL,
104 __ATOMIC_ACQUIRE) ||
105 state == Closed;
106}
107
109 TerminationDeferral terminationDeferral;
110 while (true) {
111 auto guard = m_Waiters.acquire();
112 const size_t state = __atomic_load_n(&m_State, __ATOMIC_ACQUIRE);
113 if (!(state & Closed)) {
114 panic("OperationBarrier::wait called before close.");
115 }
116 if (!(state & CountMask)) {
117 return;
118 }
119
120 const WaitQueue::WakeReason reason =
121 guard.waitForCompletion(WaitQueue::Channel(this), Thread::CallbackDrain,
122 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
123 (void)reason;
124 }
125}
126
128 close();
129 wait();
130}
131
132bool OperationBarrier::isOpen() {
133 return !(__atomic_load_n(&m_State, __ATOMIC_ACQUIRE) & Closed);
134}
135
136bool OperationBarrier::isClosedAndDrained() {
137 auto guard = m_Waiters.acquire();
138 return __atomic_load_n(&m_State, __ATOMIC_ACQUIRE) == Closed;
139}
MUST_USE_RESULT bool tryCloseIfIdle()
MUST_USE_RESULT bool tryAcquire(Lease &lease)
MUST_USE_RESULT bool tryEnter()
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118