The Pedigree Project 0.1
RtcAlarmQueue.h
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#ifndef PEDIGREE_KERNEL_MACHINE_MACH_PC_RTCALARMQUEUE_H
9#define PEDIGREE_KERNEL_MACHINE_MACH_PC_RTCALARMQUEUE_H
10#include "pedigree/kernel/processor/types.h"
11#include "pedigree/kernel/utilities/assert.h"
12
13#include <config.h>
14
24 public:
26 template <typename Context>
27 static void* dispatchOwnerForContext(Context& context) {
28 auto* thread = context.getCurrentThread();
29 return thread ? static_cast<void*>(thread) : static_cast<void*>(&context);
30 }
31
32 class Record {
33 public:
34 Record()
35 : m_pEvent(nullptr),
36 m_Deadline(0),
37 m_pTarget(nullptr),
38 m_pNext(nullptr),
39 m_pDispatchOwner(nullptr),
40 m_bDispatching(false),
41 m_bDeferredRemoval(false) {}
42
43 void prepare(void* event, uint64_t deadline, void* target) {
44 assert(!m_pNext);
45 assert(!m_bDispatching);
46 m_pEvent = event;
47 m_Deadline = deadline;
48 m_pTarget = target;
49 m_pDispatchOwner = nullptr;
50 m_bDeferredRemoval = false;
51 }
52
53 void* event() const {
54 return m_pEvent;
55 }
56
57 uint64_t deadline() const {
58 return m_Deadline;
59 }
60
61 void* target() const {
62 return m_pTarget;
63 }
64
65 Record* next() const {
66 return m_pNext;
67 }
68
69 bool dispatching() const {
70 return m_bDispatching;
71 }
72
73 bool deferredRemoval() const {
74 return m_bDeferredRemoval;
75 }
76
77 private:
78 friend class RtcAlarmQueue;
79
80 void clear() {
81 m_pEvent = nullptr;
82 m_Deadline = 0;
83 m_pTarget = nullptr;
84 m_pDispatchOwner = nullptr;
85 m_bDispatching = false;
86 m_bDeferredRemoval = false;
87 }
88
89 void* m_pEvent;
90 uint64_t m_Deadline;
91 void* m_pTarget;
92 Record* m_pNext;
93 void* m_pDispatchOwner;
94 bool m_bDispatching;
95 bool m_bDeferredRemoval;
96 };
97
98 enum class RemovalDisposition {
99 NotFound,
100 Removed,
101 SelfDeferred,
102 RemoteInFlight,
103 };
104
105 struct Removal {
106 RemovalDisposition disposition;
107 Record* record;
108 uint64_t deadline;
109 };
110
111 RtcAlarmQueue() : m_pFirst(nullptr), m_pLast(nullptr), m_pFree(nullptr) {}
112
113 Record* takeReusable() {
114 Record* record = m_pFree;
115 if (record) {
116 m_pFree = record->m_pNext;
117 record->m_pNext = nullptr;
118 }
119 return record;
120 }
121
122 void add(Record* record) {
123 assert(record);
124 assert(record->m_pEvent);
125 assert(record->m_pTarget);
126 assert(!record->m_pNext);
127 assert(!record->m_bDispatching);
128 if (m_pLast) {
129 m_pLast->m_pNext = record;
130 } else {
131 m_pFirst = record;
132 }
133 m_pLast = record;
134 }
135
136 uint64_t nextDeadline() const {
137 uint64_t next = ~uint64_t(0);
138 for (Record* record = m_pFirst; record; record = record->m_pNext) {
139 if (!record->m_bDispatching && record->m_Deadline < next) {
140 next = record->m_Deadline;
141 }
142 }
143 return next;
144 }
145
146 Record* claimDue(uint64_t now, void* owner) {
147 assert(owner);
148 for (Record* record = m_pFirst; record; record = record->m_pNext) {
149 if (!record->m_bDispatching && record->m_Deadline <= now) {
150 record->m_bDispatching = true;
151 record->m_pDispatchOwner = owner;
152 return record;
153 }
154 }
155 return nullptr;
156 }
157
158 Removal removeFirst(void* event, void* owner) {
159 Record* previous = nullptr;
160 for (Record* record = m_pFirst; record; record = record->m_pNext) {
161 if (record->m_pEvent != event) {
162 previous = record;
163 continue;
164 }
165 if (record->m_bDispatching) {
166 if (record->m_pDispatchOwner == owner) {
167 record->m_bDeferredRemoval = true;
168 return {RemovalDisposition::SelfDeferred, nullptr, record->m_Deadline};
169 }
170 return {RemovalDisposition::RemoteInFlight, nullptr, record->m_Deadline};
171 }
172
173 const uint64_t deadline = record->m_Deadline;
174 unlink(previous, record);
175 return {RemovalDisposition::Removed, record, deadline};
176 }
177 return {RemovalDisposition::NotFound, nullptr, 0};
178 }
179
180 Record* removeAllQueued(void* event, void* owner, bool& remoteInFlight, bool& selfDeferred) {
181 Record* removed = nullptr;
182 Record* removedTail = nullptr;
183 Record* previous = nullptr;
184 Record* record = m_pFirst;
185 while (record) {
186 Record* next = record->m_pNext;
187 if (record->m_pEvent != event) {
188 previous = record;
189 record = next;
190 continue;
191 }
192 if (record->m_bDispatching) {
193 if (record->m_pDispatchOwner == owner) {
194 record->m_bDeferredRemoval = true;
195 selfDeferred = true;
196 } else {
197 remoteInFlight = true;
198 }
199 previous = record;
200 record = next;
201 continue;
202 }
203
204 unlink(previous, record);
205 record->m_pNext = nullptr;
206 if (removedTail) {
207 removedTail->m_pNext = record;
208 } else {
209 removed = record;
210 }
211 removedTail = record;
212 record = next;
213 }
214 return removed;
215 }
216
217 bool hasRemoteInFlight(void* event, void* owner) const {
218 for (Record* record = m_pFirst; record; record = record->m_pNext) {
219 if (record->m_pEvent == event && record->m_bDispatching &&
220 record->m_pDispatchOwner != owner) {
221 return true;
222 }
223 }
224 return false;
225 }
226
227 void completeDispatch(Record* record) {
228 assert(record);
229 assert(record->m_bDispatching);
230 Record* previous = nullptr;
231 Record* candidate = m_pFirst;
232 while (candidate && candidate != record) {
233 previous = candidate;
234 candidate = candidate->m_pNext;
235 }
236 assert(candidate == record);
237 unlink(previous, record);
238 recycle(record);
239 }
240
241 void recycleList(Record* records) {
242 while (records) {
243 Record* next = records->m_pNext;
244 records->m_pNext = nullptr;
245 recycle(records);
246 records = next;
247 }
248 }
249
250 Record* detachActive() {
251 Record* records = m_pFirst;
252 m_pFirst = nullptr;
253 m_pLast = nullptr;
254 return records;
255 }
256
257 Record* detachFree() {
258 Record* records = m_pFree;
259 m_pFree = nullptr;
260 return records;
261 }
262
263 size_t activeCount() const {
264 size_t count = 0;
265 for (Record* record = m_pFirst; record; record = record->m_pNext) {
266 ++count;
267 }
268 return count;
269 }
270
271 size_t freeCount() const {
272 size_t count = 0;
273 for (Record* record = m_pFree; record; record = record->m_pNext) {
274 ++count;
275 }
276 return count;
277 }
278
279 private:
280 void unlink(Record* previous, Record* record) {
281 if (previous) {
282 previous->m_pNext = record->m_pNext;
283 } else {
284 m_pFirst = record->m_pNext;
285 }
286 if (m_pLast == record) {
287 m_pLast = previous;
288 }
289 record->m_pNext = nullptr;
290 }
291
292 void recycle(Record* record) {
293 record->clear();
294 record->m_pNext = m_pFree;
295 m_pFree = record;
296 }
297
298 Record* m_pFirst;
299 Record* m_pLast;
300 Record* m_pFree;
301};
302
303#endif
static void * dispatchOwnerForContext(Context &context)