rustubs/proc/sync/
irq.rs

1use crate::proc::sync::L3Sync;
2use alloc::collections::VecDeque;
3pub static EPILOGUE_QUEUE: L3Sync<EpilogueQueue> =
4	L3Sync::new(EpilogueQueue::new());
5/// the synchronized queue for Level 2 epilogues
6pub struct EpilogueQueue {
7	pub queue: VecDeque<EpilogueEntrant>,
8}
9
10impl EpilogueQueue {
11	pub const fn new() -> Self { Self { queue: VecDeque::new() } }
12}
13
14/// describes a device interrupt handler routine. This is used to register a
15/// device driver to an interrupt line (see plugbox). Device drivers code should
16/// implement the [IRQHandler] or [IRQHandlerEpilogue] trait.
17#[derive(Copy, Clone)]
18pub struct IRQGate {
19	prologue: unsafe fn(),
20	epilogue_entrant: Option<EpilogueEntrant>,
21}
22
23impl IRQGate {
24	pub unsafe fn call_prologue(&self) { (self.prologue)(); }
25	/// the epilogue function should never be directly called from the IRQGate.
26	/// Instead you need to get an epilogue entrant, and insert it into the
27	/// epilogue queue, so that the execution of epilogues are synchronized.
28	pub fn get_epilogue(&self) -> Option<EpilogueEntrant> {
29		return self.epilogue_entrant;
30	}
31}
32
33/// should epilogue take parameter(s)? if so, the parameters should be stored in
34/// the EpilogueEntrant objects but how to make it generic in a strongly typed
35/// system? Since each epilogue may require different parameter types.. passing
36/// raw pointers isn't an option because memory (ownership) safety
37#[derive(Copy, Clone)]
38pub struct EpilogueEntrant {
39	epilogue: unsafe fn(),
40}
41
42impl EpilogueEntrant {
43	/// call the actuall epilogue routine. unsafe because this must be
44	/// synchronized in L2
45	pub unsafe fn call(&self) { (self.epilogue)(); }
46}
47
48/// device driver trait that has only prologue
49pub trait IRQHandler {
50	/// the "hardirq" part of the irq handler, it must not be interrupted.
51	/// unsafe: **must guarantee the prologue is called with irq disabled**
52	/// the prologue should be short and bounded. It must not block.
53	unsafe fn do_prologue();
54	/// returns an IRQGate to be registered with the plugbox
55	fn get_gate() -> IRQGate {
56		IRQGate {
57			prologue: Self::do_prologue,
58			epilogue_entrant: None,
59		}
60	}
61}
62
63/// device driver trait with both prologue and epilogue
64pub trait IRQHandlerEpilogue {
65	/// same as in [IRQHandler]
66	unsafe fn do_prologue();
67	/// the "softirq" part of the irq handler, it allows interrupts but all
68	/// epilogues must be linearized, therefore an **context swap must not
69	/// happen when there is a running epilogue**.
70	unsafe fn do_epilogue();
71	fn get_gate() -> IRQGate {
72		IRQGate {
73			prologue: Self::do_prologue,
74			epilogue_entrant: Some(EpilogueEntrant {
75				epilogue: Self::do_epilogue,
76			}),
77		}
78	}
79}