The Pedigree Project 0.1
interrupt-manager-regressions.cc
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#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/processor/InterruptHandler.h"
11#include "pedigree/kernel/processor/InterruptManager.h"
12#include "pedigree/kernel/processor/Processor.h"
13
14#include <signal.h>
15
16#include "system/kernel/core/processor/hosted/InterruptManager.h"
17
18namespace {
19constexpr size_t TestSignal = SIGWINCH;
20
21bool check(bool condition, const char* detail) {
22 if (condition) {
23 return true;
24 }
25
26 ERROR("HOSTED-WAIT-TEST: FAIL interrupt-manager-lock-independent: " << detail);
27 return false;
28}
29
30class CountingHandler : public InterruptHandler {
31 public:
32 explicit CountingHandler(size_t identity)
33 : m_Identity(identity),
34 calls(0),
35 observedIdentity(0),
36 observedSignal(0),
37 observedContext(static_cast<size_t>(ExecutionContext::AtomicThread)) {}
38
39 void interrupt(size_t interruptNumber, InterruptState&) override {
40 observedIdentity = m_Identity;
41 observedSignal = interruptNumber;
42 observedContext = static_cast<size_t>(Processor::executionContext());
43 calls += 1;
44 }
45
46 const size_t m_Identity;
47 Atomic<size_t> calls;
48 Atomic<size_t> observedIdentity;
49 Atomic<size_t> observedSignal;
50 Atomic<size_t> observedContext;
51};
52
53Atomic<size_t> g_MutationHookCalls(0);
54Atomic<size_t> g_RaiseSucceeded(0);
55
56void dispatchWhileMutationLocked() {
57 g_MutationHookCalls += 1;
58 if (::raise(TestSignal) == 0) {
59 // raise() returns only after the synchronous production dispatch path
60 // has returned, so reaching here proves it did not wait on m_Lock.
61 g_RaiseSucceeded += 1;
62 }
63}
64} // namespace
65
66bool runHostedInterruptManagerRegressions() {
68 CountingHandler first(1);
69 CountingHandler second(2);
70
71 g_MutationHookCalls = 0;
72 g_RaiseSucceeded = 0;
73
74 const bool firstInstalled = manager.registerInterruptHandler(TestSignal, &first);
75 const bool duplicateRejected = !manager.registerInterruptHandler(TestSignal, &second);
76 if (firstInstalled) {
77 HostedInterruptManager::withMutationLockForTest(dispatchWhileMutationLocked);
78 }
79
80 const bool firstRemoved = firstInstalled && manager.registerInterruptHandler(TestSignal, nullptr);
81 const bool emptyRemovalRejected =
82 firstRemoved && !manager.registerInterruptHandler(TestSignal, nullptr);
83 const bool secondInstalled =
84 firstRemoved && manager.registerInterruptHandler(TestSignal, &second);
85 if (secondInstalled) {
86 HostedInterruptManager::withMutationLockForTest(dispatchWhileMutationLocked);
87 }
88 const bool secondRemoved =
89 secondInstalled && manager.registerInterruptHandler(TestSignal, nullptr);
90 const bool restoredToWaitable = Processor::executionContext() == ExecutionContext::WaitableThread;
91
92 bool passed = true;
93 passed &= check(firstInstalled && duplicateRejected && firstRemoved && emptyRemovalRejected &&
94 secondInstalled && secondRemoved,
95 "install/remove exclusivity changed");
96 passed &= check(g_MutationHookCalls == 2 && g_RaiseSucceeded == 2,
97 "production dispatch did not return while the mutation lock was held");
98 passed &= check(first.calls == 1 && first.observedIdentity == 1 &&
99 first.observedSignal == TestSignal && second.calls == 1 &&
100 second.observedIdentity == 2 && second.observedSignal == TestSignal,
101 "dispatch observed a stale or invalid handler publication");
102 passed &= check(
103 first.observedContext == static_cast<size_t>(ExecutionContext::HostedSyntheticIrq) &&
104 second.observedContext == static_cast<size_t>(ExecutionContext::HostedSyntheticIrq) &&
105 restoredToWaitable,
106 "hosted signal context leaked or was not classified");
107
108 if (passed) {
109 NOTICE("HOSTED-WAIT-TEST: PASS interrupt-manager-lock-independent");
110 }
111 return passed;
112}
Abstract base class for interrupt-handlers.
Handles interrupts and interrupt registrations from kernel components.
static EXPORTED_PUBLIC InterruptManager & instance()
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
static ExecutionContext executionContext()
Definition Processor.cc:109