The Pedigree Project 0.1
ThreadedIrqDispatcher.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_THREADEDIRQDISPATCHER_H
9#define PEDIGREE_KERNEL_MACHINE_THREADEDIRQDISPATCHER_H
10#include "pedigree/kernel/Spinlock.h"
11#include "pedigree/kernel/compiler.h"
12#include "pedigree/kernel/process/SchedulerWorkerWake.h"
13#include "pedigree/kernel/process/WaitQueue.h"
14#include "pedigree/kernel/processor/types.h"
15#include "pedigree/kernel/utilities/StaticString.h"
16#include "pedigree/kernel/utilities/String.h"
17
18#include <config.h>
19
20class Thread;
22class Pic;
24
35class EXPORTED_PUBLIC ThreadedIrqDispatcher {
36 public:
37 static constexpr size_t MaxLines = 17;
38 using DispatchCallback = void (*)(void*, uint8_t, size_t);
44 using RemoteWakeCallback = bool (*)(void*, uint8_t, size_t);
45
46 ThreadedIrqDispatcher(const String& name, size_t lineCount, DispatchCallback callback,
47 void* callbackContext);
49
51 bool initialise();
52
54 bool shutdown();
55
57 bool canShutdown() const;
58
59 bool isInitialised() const;
60
62 bool isCurrentWorker() const;
63
71 bool publishFromInterrupt(uint8_t line, size_t cookie);
72
73#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
74 using PublicationObservedHook = void (*)(ThreadedIrqDispatcher*, uint8_t, size_t, size_t);
75 using PendingScanAdmittedHook = void (*)(ThreadedIrqDispatcher*, uint8_t);
76
78 void setPublicationObservedHookForTest(PublicationObservedHook hook);
79
81 bool setPendingSlotCountForTest(size_t slotCount);
82
84 bool publishFromSlotForTest(uint8_t line, size_t slot, size_t cookie);
85
87 void rejectNextPublicationForTest();
88
90 void setPendingScanAdmittedHookForTest(PendingScanAdmittedHook hook);
91
93 size_t remotePublicationRejectionsForTest() const {
94 return __atomic_load_n(&m_RemotePublicationRejectionsForTest, __ATOMIC_ACQUIRE);
95 }
96
98 MUST_USE_RESULT bool setRemoteWakeCallbackForTest(RemoteWakeCallback callback,
99 void* callbackContext) {
100 // Hosted smoke modules are dynamically loaded, so keep this setup
101 // hook inline rather than adding a production-exported test symbol.
102 m_ConfigurationLock.acquire();
103 if (__atomic_load_n(&m_ConfigurationClosed, __ATOMIC_ACQUIRE)) {
104 m_ConfigurationLock.release();
105 return false;
106 }
107
108 m_RemoteWakeCallback = callback;
109 m_RemoteWakeCallbackContext = callbackContext;
110 m_ConfigurationLock.release();
111 return true;
112 }
113#endif
114
116 bool hasPending(uint8_t line) const;
117
119 size_t pendingCookie(uint8_t line) const;
120 size_t activeCookie(uint8_t line) const;
121 size_t completedBatches(uint8_t line) const;
122 size_t completedCookie(uint8_t line) const;
123 uintptr_t workerIdentity(uint8_t line) const;
124 bool callbackActive(uint8_t line) const;
125 bool publicationClosed(uint8_t line) const;
126
131 void snapshotDiagnostics(uint8_t line, IrqLineDiagnosticSnapshot& snapshot) const;
132
133 private:
134 friend class Pic;
135
141 MUST_USE_RESULT bool setRemoteWakeCallback(RemoteWakeCallback callback, void* callbackContext);
142
143 class Line {
144 public:
145 Line();
146 ~Line();
147
148 void configure(ThreadedIrqDispatcher* owner, uint8_t line, DispatchCallback callback,
149 void* callbackContext);
150 bool start();
151 void beginStop();
152 bool join();
153 bool publishFromInterrupt(size_t cookie);
154 bool hasPending() const;
155 bool isWorker(const Thread* thread) const;
156 size_t pendingCookie() const;
157 size_t activeCookie() const;
158 size_t completedBatches() const;
159 size_t completedCookie() const;
160 uintptr_t workerIdentity() const;
161 bool callbackActive() const;
162 bool publicationClosed() const;
163 void snapshotDiagnostics(IrqLineDiagnosticSnapshot& snapshot) const;
164
165 private:
166 static constexpr size_t PublicationClosed = static_cast<size_t>(1)
167 << ((sizeof(size_t) * 8) - 1);
168 static constexpr size_t PublicationCountMask = ~PublicationClosed;
169
170 static int workerEntry(void* context);
171 int run();
172 bool hasPendingForWorker() const;
173 size_t pendingCookieForWorker() const;
174 size_t takePendingCookie();
175 static bool generationReached(size_t current, size_t target);
176
177 ThreadedIrqDispatcher* m_Owner;
178 DispatchCallback m_Callback;
179 void* m_CallbackContext;
180 Thread* m_Thread;
181 PerProcessorScheduler* m_Scheduler;
182 WaitQueue m_WorkerWaiters;
183 SchedulerWorkerWake m_WorkerWake;
184 size_t m_WorkerProcessor;
185 uint8_t m_Line;
186 size_t* m_PendingCookies;
187 size_t m_PendingCookieCount;
188 size_t m_ActiveCookie;
189 size_t m_CallbackActive;
190 mutable size_t m_PublicationState;
191 size_t m_Started;
192 size_t m_CompletedBatches;
193 size_t m_CompletedCookie;
194 size_t m_PendingSinceTimestamp;
195 size_t m_ActiveCallbackStartedTimestamp;
196 size_t m_LastWakeLatency;
197 size_t m_MaximumWakeLatency;
198 size_t m_LastCallbackRuntime;
199 size_t m_MaximumCallbackRuntime;
200
201 Line(const Line&) = delete;
202 Line& operator=(const Line&) = delete;
203 };
204
205 Line m_Lines[MaxLines];
209 size_t m_LineCount;
210 DispatchCallback m_Callback;
211 void* m_CallbackContext;
216 void* m_RemoteWakeCallbackContext;
219 size_t m_Initialised;
222#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
223 PublicationObservedHook m_PublicationObservedHook;
224 PendingScanAdmittedHook m_PendingScanAdmittedHook;
225 size_t m_PendingSlotCountForTest;
226 size_t m_PublicationSlotForTest;
227 size_t m_RejectNextPublicationForTest;
228 size_t m_RemotePublicationRejectionsForTest;
229#endif
230
232 ThreadedIrqDispatcher& operator=(const ThreadedIrqDispatcher&) = delete;
233};
234
235#endif
Definition Pic.h:50
RemoteWakeCallback m_RemoteWakeCallback
bool(*)(void *, uint8_t, size_t) RemoteWakeCallback