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}