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 = 64;
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(bool lazy = false);
52
58 bool prepareLine(uint8_t line, size_t processor);
59
61 bool shutdown();
62
64 bool canShutdown() const;
65
66 bool isInitialised() const;
67
69 bool isCurrentWorker() const;
70
78 bool publishFromInterrupt(uint8_t line, size_t cookie);
79
80#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
81 using PublicationObservedHook = void (*)(ThreadedIrqDispatcher*, uint8_t, size_t, size_t);
82 using PendingScanAdmittedHook = void (*)(ThreadedIrqDispatcher*, uint8_t);
83
85 void setPublicationObservedHookForTest(PublicationObservedHook hook);
86
88 bool setPendingSlotCountForTest(size_t slotCount);
89
91 bool publishFromSlotForTest(uint8_t line, size_t slot, size_t cookie);
92
94 void rejectNextPublicationForTest();
95
97 void setPendingScanAdmittedHookForTest(PendingScanAdmittedHook hook);
98
100 size_t remotePublicationRejectionsForTest() const {
101 return __atomic_load_n(&m_RemotePublicationRejectionsForTest, __ATOMIC_ACQUIRE);
102 }
103
105 MUST_USE_RESULT bool setRemoteWakeCallbackForTest(RemoteWakeCallback callback,
106 void* callbackContext) {
107 // Hosted smoke modules are dynamically loaded, so keep this setup
108 // hook inline rather than adding a production-exported test symbol.
109 m_ConfigurationLock.acquire();
110 if (__atomic_load_n(&m_ConfigurationClosed, __ATOMIC_ACQUIRE)) {
111 m_ConfigurationLock.release();
112 return false;
113 }
114
115 m_RemoteWakeCallback = callback;
116 m_RemoteWakeCallbackContext = callbackContext;
117 m_ConfigurationLock.release();
118 return true;
119 }
120#endif
121
123 bool hasPending(uint8_t line) const;
124
126 size_t pendingCookie(uint8_t line) const;
127 size_t activeCookie(uint8_t line) const;
128 size_t completedBatches(uint8_t line) const;
129 size_t completedCookie(uint8_t line) const;
130 uintptr_t workerIdentity(uint8_t line) const;
131 bool callbackActive(uint8_t line) const;
132 bool publicationClosed(uint8_t line) const;
133
138 void snapshotDiagnostics(uint8_t line, IrqLineDiagnosticSnapshot& snapshot) const;
139
140 private:
141 friend class Pic;
142
148 MUST_USE_RESULT bool setRemoteWakeCallback(RemoteWakeCallback callback, void* callbackContext);
149
150 class Line {
151 public:
152 Line();
153 ~Line();
154
155 void configure(ThreadedIrqDispatcher* owner, uint8_t line, DispatchCallback callback,
156 void* callbackContext);
157 bool start(size_t processor);
158 void beginStop();
159 bool join();
160 bool publishFromInterrupt(size_t cookie);
161 bool hasPending() const;
162 bool isWorker(const Thread* thread) const;
163 size_t pendingCookie() const;
164 size_t activeCookie() const;
165 size_t completedBatches() const;
166 size_t completedCookie() const;
167 uintptr_t workerIdentity() const;
168 bool callbackActive() const;
169 bool publicationClosed() const;
170 void snapshotDiagnostics(IrqLineDiagnosticSnapshot& snapshot) const;
171
172 private:
173 static constexpr size_t PublicationClosed = static_cast<size_t>(1)
174 << ((sizeof(size_t) * 8) - 1);
175 static constexpr size_t PublicationCountMask = ~PublicationClosed;
176
177 static int workerEntry(void* context);
178 int run();
179 bool hasPendingForWorker() const;
180 size_t pendingCookieForWorker() const;
181 size_t takePendingCookie();
182 static bool generationReached(size_t current, size_t target);
183
184 ThreadedIrqDispatcher* m_Owner;
185 DispatchCallback m_Callback;
186 void* m_CallbackContext;
187 Thread* m_Thread;
188 PerProcessorScheduler* m_Scheduler;
189 WaitQueue m_WorkerWaiters;
190 SchedulerWorkerWake m_WorkerWake;
191 size_t m_WorkerProcessor;
192 uint8_t m_Line;
193 size_t* m_PendingCookies;
194 size_t m_PendingCookieCount;
195 size_t m_ActiveCookie;
196 size_t m_CallbackActive;
197 mutable size_t m_PublicationState;
198 size_t m_Started;
199 size_t m_CompletedBatches;
200 size_t m_CompletedCookie;
201 size_t m_PendingSinceTimestamp;
202 size_t m_ActiveCallbackStartedTimestamp;
203 size_t m_LastWakeLatency;
204 size_t m_MaximumWakeLatency;
205 size_t m_LastCallbackRuntime;
206 size_t m_MaximumCallbackRuntime;
207
208 Line(const Line&) = delete;
209 Line& operator=(const Line&) = delete;
210 };
211
217 size_t m_LineCount;
218 DispatchCallback m_Callback;
219 void* m_CallbackContext;
224 void* m_RemoteWakeCallbackContext;
227 size_t m_Initialised;
232#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
233 PublicationObservedHook m_PublicationObservedHook;
234 PendingScanAdmittedHook m_PendingScanAdmittedHook;
235 size_t m_PendingSlotCountForTest;
236 size_t m_PublicationSlotForTest;
237 size_t m_RejectNextPublicationForTest;
238 size_t m_RemotePublicationRejectionsForTest;
239#endif
240
242 ThreadedIrqDispatcher& operator=(const ThreadedIrqDispatcher&) = delete;
243};
244
245#endif
Definition Pic.h:52
RemoteWakeCallback m_RemoteWakeCallback
bool(*)(void *, uint8_t, size_t) RemoteWakeCallback