8#include "pedigree/kernel/ActivityDiagnostics.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/machine/IrqManager.h"
11#include "pedigree/kernel/machine/ThreadedIrqDispatcher.h"
12#include "pedigree/kernel/process/PerProcessorScheduler.h"
13#include "pedigree/kernel/process/Scheduler.h"
14#include "pedigree/kernel/process/TerminationDeferral.h"
15#include "pedigree/kernel/process/Thread.h"
16#include "pedigree/kernel/processor/Processor.h"
17#include "pedigree/kernel/processor/ProcessorInformation.h"
18#include "pedigree/kernel/time/Time.h"
20static_assert(__atomic_always_lock_free(
sizeof(
size_t),
nullptr),
21 "IRQ doorbell words must be lock-free");
22static_assert(__atomic_always_lock_free(
sizeof(uintptr_t),
nullptr),
23 "IRQ diagnostic identities must be lock-free");
25 "IRQ worker debug state must be lock-free");
28size_t elapsedSince(
size_t now,
size_t then) {
29 return then && now >= then ? now - then : 0;
32void updateMaximum(
size_t& maximum,
size_t value) {
33 if (value > __atomic_load_n(&maximum, __ATOMIC_RELAXED)) {
35 __atomic_store_n(&maximum, value, __ATOMIC_RELEASE);
42 return IrqWorkerDebugState::None;
44 return IrqWorkerDebugState::SemaphoreWait;
45 case Thread::CondWait:
46 return IrqWorkerDebugState::ConditionWait;
48 return IrqWorkerDebugState::Joining;
49 case Thread::FutexWait:
50 return IrqWorkerDebugState::FutexWait;
51 case Thread::EventWait:
52 return IrqWorkerDebugState::EventWait;
53 case Thread::ProcessWait:
54 return IrqWorkerDebugState::ProcessWait;
55 case Thread::CallbackDrain:
56 return IrqWorkerDebugState::CallbackDrain;
58 return IrqWorkerDebugState::Unavailable;
63 case WaitQueue::WakeReason::Waiting:
64 return IrqWorkerWaitReason::Waiting;
65 case WaitQueue::WakeReason::Signalled:
66 return IrqWorkerWaitReason::Signalled;
67 case WaitQueue::WakeReason::Event:
68 return IrqWorkerWaitReason::Event;
69 case WaitQueue::WakeReason::Unwinding:
70 return IrqWorkerWaitReason::Unwinding;
71 case WaitQueue::WakeReason::Terminating:
72 return IrqWorkerWaitReason::Terminating;
73 case WaitQueue::WakeReason::Spurious:
74 return IrqWorkerWaitReason::Spurious;
76 return IrqWorkerWaitReason::Unavailable;
80ThreadedIrqDispatcher::Line::Line()
83 m_CallbackContext(nullptr),
90 m_PendingCookies(nullptr),
91 m_PendingCookieCount(0),
94 m_PublicationState(PublicationClosed),
96 m_CompletedBatches(0),
98 m_PendingSinceTimestamp(0),
99 m_ActiveCallbackStartedTimestamp(0),
100 m_LastWakeLatency(0),
101 m_MaximumWakeLatency(0),
102 m_LastCallbackRuntime(0),
103 m_MaximumCallbackRuntime(0) {}
105ThreadedIrqDispatcher::Line::~Line() {
106 if (__atomic_load_n(&m_Started, __ATOMIC_ACQUIRE) ||
107 __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE) || m_PendingCookies) {
108 FATAL(
"A threaded IRQ worker was destroyed while active.");
113 DispatchCallback callback,
void* callbackContext) {
116 m_Callback = callback;
117 m_CallbackContext = callbackContext;
120bool ThreadedIrqDispatcher::Line::start() {
122 if (__atomic_load_n(&m_Started, __ATOMIC_ACQUIRE) ||
123 __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE) || m_PendingCookies || !m_Owner || !m_Callback) {
128#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
129 const size_t testPendingCookieCount =
130 __atomic_load_n(&m_Owner->m_PendingSlotCountForTest, __ATOMIC_ACQUIRE);
131 if (testPendingCookieCount) {
132 pendingCookieCount = testPendingCookieCount;
135 if (!pendingCookieCount) {
138 size_t* pendingCookies =
new size_t[pendingCookieCount];
139 for (
size_t i = 0; i < pendingCookieCount; ++i) {
140 __atomic_store_n(&pendingCookies[i],
static_cast<size_t>(0), __ATOMIC_RELAXED);
142 m_PendingCookies = pendingCookies;
143 m_PendingCookieCount = pendingCookieCount;
144 __atomic_store_n(&m_ActiveCookie,
static_cast<size_t>(0), __ATOMIC_RELEASE);
145 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(0), __ATOMIC_RELEASE);
146 __atomic_store_n(&m_PublicationState,
static_cast<size_t>(0), __ATOMIC_RELEASE);
147 __atomic_store_n(&m_CompletedBatches,
static_cast<size_t>(0), __ATOMIC_RELEASE);
148 __atomic_store_n(&m_CompletedCookie,
static_cast<size_t>(0), __ATOMIC_RELEASE);
149 __atomic_store_n(&m_PendingSinceTimestamp,
static_cast<size_t>(0), __ATOMIC_RELEASE);
150 __atomic_store_n(&m_ActiveCallbackStartedTimestamp,
static_cast<size_t>(0), __ATOMIC_RELEASE);
151 __atomic_store_n(&m_LastWakeLatency,
static_cast<size_t>(0), __ATOMIC_RELEASE);
152 __atomic_store_n(&m_MaximumWakeLatency,
static_cast<size_t>(0), __ATOMIC_RELEASE);
153 __atomic_store_n(&m_LastCallbackRuntime,
static_cast<size_t>(0), __ATOMIC_RELEASE);
154 __atomic_store_n(&m_MaximumCallbackRuntime,
static_cast<size_t>(0), __ATOMIC_RELEASE);
164 __atomic_store_n(&m_Thread, thread, __ATOMIC_RELEASE);
165 const String workerName(
static_cast<const char*
>(m_Owner->m_Name), m_Owner->m_Name.length());
166 thread->setName(workerName);
167 m_Scheduler->registerWorkerWake(m_WorkerWake, m_WorkerWaiters);
169 __atomic_store_n(&m_Started,
static_cast<size_t>(1), __ATOMIC_RELEASE);
170 if (!thread->
start()) {
174 FATAL(
"A threaded IRQ worker could not be started.");
183void ThreadedIrqDispatcher::Line::beginStop() {
184 if (!__atomic_load_n(&m_Started, __ATOMIC_ACQUIRE)) {
189 __atomic_fetch_or(&m_PublicationState, PublicationClosed, __ATOMIC_ACQ_REL);
190 m_Scheduler->ringIrqWorkDoorbell(m_WorkerWake);
193bool ThreadedIrqDispatcher::Line::join() {
194 if (!__atomic_load_n(&m_Started, __ATOMIC_ACQUIRE)) {
195 return __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE) ==
nullptr;
198 Thread* thread = __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE);
204 m_Scheduler->unregisterWorkerWake(m_WorkerWake);
206 __atomic_store_n(&m_Thread,
static_cast<Thread*
>(
nullptr), __ATOMIC_RELEASE);
207 m_Scheduler =
nullptr;
208 __atomic_store_n(&m_Started,
static_cast<size_t>(0), __ATOMIC_RELEASE);
209 delete[] m_PendingCookies;
210 m_PendingCookies =
nullptr;
211 m_PendingCookieCount = 0;
212 __atomic_store_n(&m_ActiveCookie,
static_cast<size_t>(0), __ATOMIC_RELEASE);
213 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(0), __ATOMIC_RELEASE);
217bool ThreadedIrqDispatcher::Line::publishFromInterrupt(
size_t cookie) {
223#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
224 const size_t processorSlot =
225 __atomic_load_n(&m_Owner->m_PublicationSlotForTest, __ATOMIC_ACQUIRE);
226 if (processorSlot !=
static_cast<size_t>(-1)) {
227 processor = processorSlot;
231 const bool remoteProducer = processor != m_WorkerProcessor;
232 if (remoteProducer && !m_Owner->m_RemoteWakeCallback) {
233#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
234 __atomic_add_fetch(&m_Owner->m_RemotePublicationRejectionsForTest,
static_cast<size_t>(1),
243 const size_t admission =
244 __atomic_fetch_add(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_ACQ_REL);
245 if (admission & PublicationClosed) {
246 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
250 if (!m_PendingCookies || processor >= m_PendingCookieCount) {
251 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
262 const size_t pending =
263 __atomic_exchange_n(&m_PendingCookies[processor], cookie, __ATOMIC_ACQ_REL);
265 __atomic_store_n(&m_PendingSinceTimestamp,
static_cast<size_t>(Time::getTicks()),
269#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
270 PublicationObservedHook hook =
271 __atomic_load_n(&m_Owner->m_PublicationObservedHook, __ATOMIC_ACQUIRE);
273 hook(m_Owner, m_Line, cookie, pending);
281 m_Scheduler->ringIrqWorkDoorbell(m_WorkerWake);
282 if (remoteProducer && !pending) {
283 if (!m_Owner->m_RemoteWakeCallback(m_Owner->m_RemoteWakeCallbackContext, m_Line,
284 m_WorkerProcessor)) {
288 FATAL_NOLOCK(
"Threaded IRQ remote worker prompt failed after publication.");
292 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
296bool ThreadedIrqDispatcher::Line::hasPending()
const {
300bool ThreadedIrqDispatcher::Line::isWorker(
const Thread* thread)
const {
301 return thread && thread == __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE);
304size_t ThreadedIrqDispatcher::Line::pendingCookie()
const {
308 const size_t admission =
309 __atomic_fetch_add(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_ACQ_REL);
310 if (admission & PublicationClosed) {
311 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
315#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
316 PendingScanAdmittedHook hook =
317 __atomic_load_n(&m_Owner->m_PendingScanAdmittedHook, __ATOMIC_ACQUIRE);
319 hook(m_Owner, m_Line);
323 const size_t pending = pendingCookieForWorker();
324 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
328size_t ThreadedIrqDispatcher::Line::pendingCookieForWorker()
const {
330 for (
size_t i = 0; i < m_PendingCookieCount; ++i) {
331 const size_t candidate = __atomic_load_n(&m_PendingCookies[i], __ATOMIC_ACQUIRE);
332 if (candidate && (!newest || generationReached(candidate, newest))) {
339size_t ThreadedIrqDispatcher::Line::activeCookie()
const {
340 return __atomic_load_n(&m_ActiveCookie, __ATOMIC_ACQUIRE);
343size_t ThreadedIrqDispatcher::Line::completedBatches()
const {
344 return __atomic_load_n(&m_CompletedBatches, __ATOMIC_ACQUIRE);
347size_t ThreadedIrqDispatcher::Line::completedCookie()
const {
348 return __atomic_load_n(&m_CompletedCookie, __ATOMIC_ACQUIRE);
351uintptr_t ThreadedIrqDispatcher::Line::workerIdentity()
const {
352 return reinterpret_cast<uintptr_t
>(__atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE));
355bool ThreadedIrqDispatcher::Line::callbackActive()
const {
356 return __atomic_load_n(&m_CallbackActive, __ATOMIC_ACQUIRE) != 0;
359bool ThreadedIrqDispatcher::Line::publicationClosed()
const {
360 return (__atomic_load_n(&m_PublicationState, __ATOMIC_ACQUIRE) & PublicationClosed) != 0;
364 snapshot.workerDiagnosticAvailable =
false;
365 snapshot.workerDebugState = IrqWorkerDebugState::Unavailable;
366 snapshot.workerDebugAddress = 0;
367 snapshot.workerWaitActive =
false;
368 snapshot.workerWaitQueue = 0;
369 snapshot.workerWaitChannelOwner = 0;
370 snapshot.workerWaitChannelValue = 0;
371 snapshot.workerWaitReason = IrqWorkerWaitReason::Unavailable;
372 snapshot.workerWaitStateLevel = 0;
373 snapshot.workerWaitQueued =
false;
374 snapshot.observationTimestamp =
static_cast<size_t>(Time::getTicks());
375 snapshot.pendingSinceTimestamp = __atomic_load_n(&m_PendingSinceTimestamp, __ATOMIC_ACQUIRE);
376 snapshot.activeCallbackStartedTimestamp =
377 __atomic_load_n(&m_ActiveCallbackStartedTimestamp, __ATOMIC_ACQUIRE);
378 snapshot.lastWakeLatency = __atomic_load_n(&m_LastWakeLatency, __ATOMIC_ACQUIRE);
379 snapshot.maximumWakeLatency = __atomic_load_n(&m_MaximumWakeLatency, __ATOMIC_ACQUIRE);
380 snapshot.lastCallbackRuntime = __atomic_load_n(&m_LastCallbackRuntime, __ATOMIC_ACQUIRE);
381 snapshot.maximumCallbackRuntime = __atomic_load_n(&m_MaximumCallbackRuntime, __ATOMIC_ACQUIRE);
387 const size_t admission =
388 __atomic_fetch_add(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_ACQ_REL);
389 if (admission & PublicationClosed) {
390 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
394 Thread* thread = __atomic_load_n(&m_Thread, __ATOMIC_ACQUIRE);
396 snapshot.workerDiagnosticAvailable =
true;
397 uintptr_t debugAddress = 0;
398 snapshot.workerDebugState = workerDebugState(thread->
getDebugState(debugAddress));
399 snapshot.workerDebugAddress = debugAddress;
403 snapshot.workerWaitActive =
true;
404 snapshot.workerWaitQueue =
reinterpret_cast<uintptr_t
>(wait.queue);
405 snapshot.workerWaitChannelOwner =
reinterpret_cast<uintptr_t
>(wait.channelOwner);
406 snapshot.workerWaitChannelValue = wait.channelValue;
407 snapshot.workerWaitReason = workerWaitReason(wait.reason);
408 snapshot.workerWaitStateLevel = wait.stateLevel;
409 snapshot.workerWaitQueued = wait.queued;
413 __atomic_fetch_sub(&m_PublicationState,
static_cast<size_t>(1), __ATOMIC_RELEASE);
416int ThreadedIrqDispatcher::Line::workerEntry(
void* context) {
417 return reinterpret_cast<Line*
>(context)->run();
420int ThreadedIrqDispatcher::Line::run() {
428 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(1), __ATOMIC_RELEASE);
429 const size_t pendingSince = __atomic_load_n(&m_PendingSinceTimestamp, __ATOMIC_ACQUIRE);
430 const size_t cookie = takePendingCookie();
432 const size_t completedCookie = __atomic_load_n(&m_CompletedCookie, __ATOMIC_ACQUIRE);
433 if (completedCookie && !generationReached(cookie, completedCookie)) {
438 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(0), __ATOMIC_RELEASE);
443 const size_t started =
static_cast<size_t>(Time::getTicks());
444 const size_t wakeLatency = elapsedSince(started, pendingSince);
445 __atomic_store_n(&m_LastWakeLatency, wakeLatency, __ATOMIC_RELEASE);
446 updateMaximum(m_MaximumWakeLatency, wakeLatency);
447 __atomic_store_n(&m_ActiveCallbackStartedTimestamp, started, __ATOMIC_RELEASE);
448 __atomic_store_n(&m_ActiveCookie, cookie, __ATOMIC_RELEASE);
449 m_Callback(m_CallbackContext, m_Line, cookie);
450 const size_t completed =
static_cast<size_t>(Time::getTicks());
451 const size_t runtime = elapsedSince(completed, started);
452 ActivityDiagnostics::recordThreadedDispatch(m_Line, runtime);
453 __atomic_store_n(&m_LastCallbackRuntime, runtime, __ATOMIC_RELEASE);
454 updateMaximum(m_MaximumCallbackRuntime, runtime);
455 __atomic_add_fetch(&m_CompletedBatches,
static_cast<size_t>(1), __ATOMIC_ACQ_REL);
456 __atomic_store_n(&m_CompletedCookie, cookie, __ATOMIC_RELEASE);
457 __atomic_store_n(&m_ActiveCookie,
static_cast<size_t>(0), __ATOMIC_RELEASE);
458 __atomic_store_n(&m_ActiveCallbackStartedTimestamp,
static_cast<size_t>(0), __ATOMIC_RELEASE);
459 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(0), __ATOMIC_RELEASE);
467 __atomic_store_n(&m_CallbackActive,
static_cast<size_t>(0), __ATOMIC_RELEASE);
468 const size_t publicationState = __atomic_load_n(&m_PublicationState, __ATOMIC_ACQUIRE);
469 if (publicationState & PublicationClosed) {
470 if (publicationState & PublicationCountMask) {
478 if (!hasPendingForWorker()) {
487 auto guard = m_WorkerWaiters.acquire();
488 const size_t currentPublicationState = __atomic_load_n(&m_PublicationState, __ATOMIC_ACQUIRE);
489 if (!hasPendingForWorker() && !(currentPublicationState & PublicationClosed)) {
490 const WaitQueue::WakeReason reason =
491 guard.wait(
WaitQueue::Channel(), Thread::CondWait,
reinterpret_cast<uintptr_t
>(
this));
499bool ThreadedIrqDispatcher::Line::hasPendingForWorker()
const {
500 return pendingCookieForWorker() != 0;
503size_t ThreadedIrqDispatcher::Line::takePendingCookie() {
505 for (
size_t i = 0; i < m_PendingCookieCount; ++i) {
506 const size_t candidate =
507 __atomic_exchange_n(&m_PendingCookies[i],
static_cast<size_t>(0), __ATOMIC_ACQ_REL);
508 if (candidate && (!newest || generationReached(candidate, newest))) {
515bool ThreadedIrqDispatcher::Line::generationReached(
size_t current,
size_t target) {
518 return static_cast<intptr_t
>(current - target) >= 0;
521ThreadedIrqDispatcher::ThreadedIrqDispatcher(
const String& name,
size_t lineCount,
522 DispatchCallback callback,
void* callbackContext)
525 m_LineCount(lineCount),
526 m_Callback(callback),
527 m_CallbackContext(callbackContext),
530 m_RemoteWakeCallbackContext(nullptr),
532 m_Initialised(false),
534#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
536 m_PublicationObservedHook(nullptr),
537 m_PendingScanAdmittedHook(nullptr),
538 m_PendingSlotCountForTest(0),
539 m_PublicationSlotForTest(static_cast<size_t>(-1)),
540 m_RejectNextPublicationForTest(0),
541 m_RemotePublicationRejectionsForTest(0)
544 if (m_LineCount > MaxLines) {
545 m_LineCount = MaxLines;
550 void* callbackContext) {
560 m_RemoteWakeCallbackContext = callbackContext;
565#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
566void ThreadedIrqDispatcher::setPublicationObservedHookForTest(PublicationObservedHook hook) {
567 __atomic_store_n(&m_PublicationObservedHook, hook, __ATOMIC_RELEASE);
570bool ThreadedIrqDispatcher::setPendingSlotCountForTest(
size_t slotCount) {
571 if (isInitialised() || !slotCount) {
575 __atomic_store_n(&m_PendingSlotCountForTest, slotCount, __ATOMIC_RELEASE);
579bool ThreadedIrqDispatcher::publishFromSlotForTest(uint8_t line,
size_t slot,
size_t cookie) {
580 if (!isInitialised() || line >= m_LineCount) {
584 size_t expected =
static_cast<size_t>(-1);
585 if (!__atomic_compare_exchange_n(&m_PublicationSlotForTest, &expected, slot,
false,
586 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
589 const bool published = m_Lines[line].publishFromInterrupt(cookie);
590 __atomic_store_n(&m_PublicationSlotForTest,
static_cast<size_t>(-1), __ATOMIC_RELEASE);
594void ThreadedIrqDispatcher::rejectNextPublicationForTest() {
595 __atomic_store_n(&m_RejectNextPublicationForTest,
static_cast<size_t>(1), __ATOMIC_RELEASE);
598void ThreadedIrqDispatcher::setPendingScanAdmittedHookForTest(PendingScanAdmittedHook hook) {
599 __atomic_store_n(&m_PendingScanAdmittedHook, hook, __ATOMIC_RELEASE);
604ThreadedIrqDispatcher::~ThreadedIrqDispatcher() {
605 if (__atomic_load_n(&m_Initialised, __ATOMIC_ACQUIRE)) {
606 FATAL(
"Threaded IRQ dispatcher was destroyed before shutdown.");
612 if (__atomic_load_n(&m_Initialised, __ATOMIC_ACQUIRE) || !m_LineCount || !m_Callback) {
617 size_t configurationExpected = 0;
619 static_cast<size_t>(1),
false, __ATOMIC_ACQ_REL,
626#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
627 __atomic_store_n(&m_RejectNextPublicationForTest,
static_cast<size_t>(0), __ATOMIC_RELEASE);
628 __atomic_store_n(&m_RemotePublicationRejectionsForTest,
static_cast<size_t>(0), __ATOMIC_RELEASE);
632 for (
size_t i = 0; i < m_LineCount; ++i) {
633 m_Lines[i].configure(
this,
static_cast<uint8_t
>(i), m_Callback, m_CallbackContext);
634 if (!m_Lines[i].start()) {
635 for (
size_t j = 0; j < i; ++j) {
636 m_Lines[j].beginStop();
639 for (
size_t j = 0; j < i; ++j) {
647 __atomic_store_n(&m_Initialised,
static_cast<size_t>(1), __ATOMIC_RELEASE);
656 if (!__atomic_load_n(&m_Initialised, __ATOMIC_ACQUIRE)) {
663 if (!__atomic_compare_exchange_n(&
m_ShutdownClaimed, &expected,
static_cast<size_t>(1),
false,
664 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) {
667 return !__atomic_load_n(&m_Initialised, __ATOMIC_ACQUIRE);
670 for (
size_t i = 0; i < m_LineCount; ++i) {
671 m_Lines[i].beginStop();
677 for (
size_t i = 0; i < m_LineCount; ++i) {
678 joined &= m_Lines[i].join();
681 __atomic_store_n(&m_Initialised,
static_cast<size_t>(0), __ATOMIC_RELEASE);
699 safe = safe && !current->getHostedSignalDepth();
704bool ThreadedIrqDispatcher::isInitialised()
const {
705 return __atomic_load_n(&m_Initialised, __ATOMIC_ACQUIRE) != 0;
711 for (
size_t i = 0; i < m_LineCount; ++i) {
712 if (m_Lines[i].isWorker(current)) {
721 if (!isInitialised() || line >= m_LineCount || !cookie) {
724#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
725 if (__atomic_exchange_n(&m_RejectNextPublicationForTest,
static_cast<size_t>(0),
730 return m_Lines[line].publishFromInterrupt(cookie);
734 return isInitialised() && line < m_LineCount && m_Lines[line].hasPending();
738 return line < m_LineCount ? m_Lines[line].pendingCookie() : 0;
741size_t ThreadedIrqDispatcher::activeCookie(uint8_t line)
const {
742 return line < m_LineCount ? m_Lines[line].activeCookie() : 0;
745size_t ThreadedIrqDispatcher::completedBatches(uint8_t line)
const {
746 return line < m_LineCount ? m_Lines[line].completedBatches() : 0;
749size_t ThreadedIrqDispatcher::completedCookie(uint8_t line)
const {
750 return line < m_LineCount ? m_Lines[line].completedCookie() : 0;
753uintptr_t ThreadedIrqDispatcher::workerIdentity(uint8_t line)
const {
754 return line < m_LineCount ? m_Lines[line].workerIdentity() : 0;
757bool ThreadedIrqDispatcher::callbackActive(uint8_t line)
const {
758 return line < m_LineCount && m_Lines[line].callbackActive();
761bool ThreadedIrqDispatcher::publicationClosed(uint8_t line)
const {
762 return line < m_LineCount && m_Lines[line].publicationClosed();
767 if (line < m_LineCount) {
768 m_Lines[line].snapshotDiagnostics(snapshot);
static ProcessorInformation & information()
static ExecutionContext executionContext()
static Scheduler & instance()
bool acquire(bool recurse=false, bool safe=true)
bool getWaitDebugInfo(WaitDebugInfo &info)
DebugState getDebugState(uintptr_t &address)
Spinlock m_ConfigurationLock
bool hasPending(uint8_t line) const
size_t pendingCookie(uint8_t line) const
RemoteWakeCallback m_RemoteWakeCallback
bool isCurrentWorker() const
NormalStaticString m_Name
bool(*)(void *, uint8_t, size_t) RemoteWakeCallback
size_t m_ConfigurationClosed
bool publishFromInterrupt(uint8_t line, size_t cookie)
MUST_USE_RESULT bool setRemoteWakeCallback(RemoteWakeCallback callback, void *callbackContext)
void snapshotDiagnostics(uint8_t line, IrqLineDiagnosticSnapshot &snapshot) const