1use crate::access_policy::{Denial, ResourceId};
12use crate::hardware_backend::BackendError;
13use std::collections::BTreeMap;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct InterruptEvent {
18 pub resource: ResourceId,
20 pub sequence: u64,
22 pub count: u64,
24 pub timestamp_ns: i64,
26 pub coalesced_count: u64,
28}
29
30pub trait InterruptBackend: Send {
32 fn acknowledge(&mut self) -> Result<(), BackendError> {
34 Ok(())
35 }
36}
37
38#[derive(Clone, Debug, Default)]
40pub struct FakeInterrupt {
41 pub acks: usize,
42}
43
44impl FakeInterrupt {
45 pub fn new() -> Self {
46 Self::default()
47 }
48}
49
50impl InterruptBackend for FakeInterrupt {
51 fn acknowledge(&mut self) -> Result<(), BackendError> {
52 self.acks += 1;
53 Ok(())
54 }
55}
56
57struct Waiter {
59 after_sequence: u64,
60 sender: Box<dyn FnOnce(InterruptEvent) + Send>,
61}
62
63pub struct InterruptState {
65 pub resource: ResourceId,
66 pub sequence: u64,
67 pub count: u64,
68 pub last_timestamp_ns: i64,
69 pub coalesced_count: u64,
70 waiters: Vec<Waiter>,
71}
72
73impl InterruptState {
74 pub fn new(resource: ResourceId) -> Self {
75 Self {
76 resource,
77 sequence: 0,
78 count: 0,
79 last_timestamp_ns: 0,
80 coalesced_count: 0,
81 waiters: Vec::new(),
82 }
83 }
84
85 pub fn current_event(&self) -> InterruptEvent {
87 InterruptEvent {
88 resource: self.resource,
89 sequence: self.sequence,
90 count: self.count,
91 timestamp_ns: self.last_timestamp_ns,
92 coalesced_count: self.coalesced_count,
93 }
94 }
95}
96
97pub struct InterruptManager {
99 resources: BTreeMap<ResourceId, InterruptState>,
100}
101
102impl InterruptManager {
103 pub fn new() -> Self {
104 Self { resources: BTreeMap::new() }
105 }
106
107 pub fn register(&mut self, resource: ResourceId) {
109 self.resources.entry(resource).or_insert_with(|| InterruptState::new(resource));
110 }
111
112 pub fn is_registered(&self, resource: ResourceId) -> bool {
114 self.resources.contains_key(&resource)
115 }
116
117 pub fn on_interrupt(
122 &mut self,
123 resource: ResourceId,
124 timestamp_ns: i64,
125 backend: Option<&mut dyn InterruptBackend>,
126 ) -> Result<InterruptEvent, Denial> {
127 let state = self.resources.get_mut(&resource).ok_or(Denial::UnknownResource)?;
128 state.sequence += 1;
129 state.count += 1;
130 state.last_timestamp_ns = timestamp_ns;
131
132 let mut satisfied = Vec::new();
133 let mut remaining = Vec::new();
134 for waiter in state.waiters.drain(..) {
135 if state.sequence > waiter.after_sequence {
136 satisfied.push(waiter);
137 } else {
138 remaining.push(waiter);
139 }
140 }
141 state.waiters = remaining;
142
143 if satisfied.is_empty() {
144 state.coalesced_count += 1;
145 } else {
146 state.coalesced_count = 0;
147 }
148
149 let event = state.current_event();
150
151 for waiter in satisfied {
152 (waiter.sender)(event);
153 }
154
155 if let Some(backend) = backend {
156 let _ = backend.acknowledge();
157 }
158
159 Ok(event)
160 }
161
162 pub fn wait_for_interrupt(
167 &mut self,
168 resource: ResourceId,
169 after_sequence: u64,
170 sender: Box<dyn FnOnce(InterruptEvent) + Send>,
171 ) -> Result<Option<InterruptEvent>, Denial> {
172 let state = self.resources.get_mut(&resource).ok_or(Denial::UnknownResource)?;
173 if state.sequence > after_sequence {
174 Ok(Some(state.current_event()))
175 } else {
176 state.waiters.push(Waiter { after_sequence, sender });
177 Ok(None)
178 }
179 }
180
181 pub fn cancel_waiters(&mut self) {
183 for state in self.resources.values_mut() {
184 state.waiters.clear();
185 }
186 }
187
188 pub fn waiter_count(&self, resource: ResourceId) -> usize {
190 self.resources.get(&resource).map(|s| s.waiters.len()).unwrap_or(0)
191 }
192}
193
194impl std::fmt::Debug for InterruptState {
195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
196 f.debug_struct("InterruptState")
197 .field("resource", &self.resource)
198 .field("sequence", &self.sequence)
199 .field("count", &self.count)
200 .field("last_timestamp_ns", &self.last_timestamp_ns)
201 .field("coalesced_count", &self.coalesced_count)
202 .field("waiters", &self.waiters.len())
203 .finish()
204 }
205}
206
207impl std::fmt::Debug for InterruptManager {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 f.debug_struct("InterruptManager").field("resources", &self.resources).finish()
210 }
211}
212
213impl Default for InterruptManager {
214 fn default() -> Self {
215 Self::new()
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 use std::sync::atomic::{AtomicBool, Ordering};
223 use std::sync::{Arc, Mutex};
224
225 #[test]
226 fn test_interrupt_registration_and_trigger() {
227 let mut manager = InterruptManager::new();
228 manager.register(1);
229 assert!(manager.is_registered(1));
230 assert!(!manager.is_registered(2));
231
232 let mut fake_backend = FakeInterrupt::new();
233 let event = manager.on_interrupt(1, 100_000, Some(&mut fake_backend)).unwrap();
234 assert_eq!(event.resource, 1);
235 assert_eq!(event.sequence, 1);
236 assert_eq!(event.count, 1);
237 assert_eq!(event.timestamp_ns, 100_000);
238 assert_eq!(event.coalesced_count, 1);
239 assert_eq!(fake_backend.acks, 1);
240 }
241
242 #[test]
243 fn test_interrupt_immediate_wait_when_sequence_greater() {
244 let mut manager = InterruptManager::new();
245 manager.register(1);
246 manager.on_interrupt(1, 100_000, None).unwrap();
247
248 let called = Arc::new(AtomicBool::new(false));
249 let called_clone = called.clone();
250 let immediate = manager
251 .wait_for_interrupt(
252 1,
253 0,
254 Box::new(move |_| {
255 called_clone.store(true, Ordering::SeqCst);
256 }),
257 )
258 .unwrap();
259
260 assert!(immediate.is_some());
261 let event = immediate.unwrap();
262 assert_eq!(event.sequence, 1);
263 assert!(!called.load(Ordering::SeqCst));
264 }
265
266 #[test]
267 fn test_interrupt_waiter_satisfied_on_trigger() {
268 let mut manager = InterruptManager::new();
269 manager.register(1);
270
271 let received = Arc::new(Mutex::new(None));
272 let received_clone = received.clone();
273 let immediate = manager
274 .wait_for_interrupt(
275 1,
276 0,
277 Box::new(move |event| {
278 *received_clone.lock().unwrap() = Some(event);
279 }),
280 )
281 .unwrap();
282
283 assert!(immediate.is_none());
284 assert_eq!(manager.waiter_count(1), 1);
285
286 let mut fake_backend = FakeInterrupt::new();
287 manager.on_interrupt(1, 200_000, Some(&mut fake_backend)).unwrap();
288
289 assert_eq!(manager.waiter_count(1), 0);
290 let event = received.lock().unwrap().take().expect("waiter should receive event");
291 assert_eq!(event.sequence, 1);
292 assert_eq!(event.count, 1);
293 assert_eq!(event.timestamp_ns, 200_000);
294 assert_eq!(event.coalesced_count, 0);
295 assert_eq!(fake_backend.acks, 1);
296 }
297
298 #[test]
299 fn test_interrupt_cancel_waiters() {
300 let mut manager = InterruptManager::new();
301 manager.register(1);
302
303 manager.wait_for_interrupt(1, 0, Box::new(|_| {})).unwrap();
304 assert_eq!(manager.waiter_count(1), 1);
305
306 manager.cancel_waiters();
307 assert_eq!(manager.waiter_count(1), 0);
308 }
309}