The Pedigree Project 0.1
Rcu.cc
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/Rcu.h"
4#include "pedigree/kernel/process/TerminationDeferral.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/ProcessorInformation.h"
7
8RcuReadGuard::RcuReadGuard() : m_State(nullptr), m_Interrupts(Processor::getInterrupts()) {
10 if (Processor::m_Initialised != 2) {
11 panic("RCU requires completed processor discovery.");
12 }
13#if HOSTED
14 if (!Processor::onHostedExecutionThread()) {
15 panic("RCU guard requires the hosted execution thread.");
16 }
17#endif
18 m_State = &Processor::information().rcuState();
19 m_State->enter();
20}
21
22RcuReadGuard::~RcuReadGuard() {
23 if (Processor::getInterrupts() || &Processor::information().rcuState() != m_State) {
24 panic("RCU reader changed its execution context.");
25 }
26 m_State->leave();
27 Processor::setInterrupts(m_Interrupts);
28}
29
30void Rcu::synchronize() {
31 if (Processor::m_Initialised != 2 || Processor::information().rcuState().active()) {
32 panic("RCU grace period requires initialized processors and no local reader.");
33 }
34 // SC publication, reader admission/load, and these snapshots share an order:
35 // a reader of an old pointer is either visible here or has already finished.
36 for (size_t i = 0; i < Processor::getCount(); ++i) {
37 RcuReadState& state = Processor::informationAt(i)->rcuState();
38 const auto before = state.snapshot();
39 while (!state.passed(before)) {
41 }
42 }
43}
44
45RcuRetireQueue::~RcuRetireQueue() {
46 drain();
47}
48
49void RcuRetireQueue::retire(void* object, Reclaim reclaim) {
50 if (!reclaim || Processor::information().rcuState().active() ||
51 !Processor::information().getCurrentThread() || !Processor::getInterrupts() ||
53 panic("RCU retirement requires a callback and ordinary task context.");
54 }
55 TerminationDeferral lifetime;
56 LockGuard<Mutex> lock(m_Lock);
57 if (m_Count == Capacity) {
58 drainLocked();
59 }
60 m_Entries[m_Count++] = {object, reclaim};
61}
62
63void RcuRetireQueue::drain() {
64 if (Processor::information().rcuState().active() || !Processor::getInterrupts() ||
65 !Processor::information().getCurrentThread() || Processor::inDeviceHardIrq()) {
66 panic("RCU reclamation requires ordinary task context.");
67 }
68 TerminationDeferral lifetime;
69 LockGuard<Mutex> lock(m_Lock);
70 drainLocked();
71}
72
73void RcuRetireQueue::drainLocked() {
74 if (!m_Count) {
75 return;
76 }
77 Rcu::synchronize();
78 for (size_t i = 0; i < m_Count; ++i) {
79 m_Entries[i].reclaim(m_Entries[i].object);
80 }
81 m_Count = 0;
82}
static bool getInterrupts()
static ProcessorInformation & information()
static size_t getCount()
static void pause()
static size_t m_Initialised
Definition Processor.h:475
static bool inDeviceHardIrq()
Definition Processor.h:565
static ProcessorInformation * informationAt(size_t cpu)
Definition Processor.cc:39
static void setInterrupts(bool bEnable)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:117