Skip to main content

ax_sync/
context.rs

1//! Execution-context guards used by synchronization adapters.
2
3use core::marker::PhantomData;
4
5use crate::interface::{CONTEXT_IRQSAVE, CONTEXT_PREEMPT, CONTEXT_PREEMPT_IRQSAVE, CONTEXT_RAW};
6
7/// Saves the local interrupt state and disables local interrupts.
8#[doc(hidden)]
9#[inline(always)]
10pub fn irq_save_and_disable() -> usize {
11    crate::interface::context_enter(CONTEXT_IRQSAVE)
12}
13
14/// Restores a local interrupt state returned by [`irq_save_and_disable`].
15///
16/// # Safety
17///
18/// `state` must come from the matching save operation on the current CPU and
19/// must be restored exactly once, in properly nested order.
20#[doc(hidden)]
21#[inline(always)]
22pub unsafe fn irq_restore(state: usize) {
23    crate::interface::context_exit(CONTEXT_IRQSAVE, state);
24}
25
26/// Internal critical-section contract retained for low-level adapters.
27#[doc(hidden)]
28pub trait GuardState {
29    /// Saved state needed when the guard is released.
30    type State: Clone + Copy;
31
32    /// Enters the critical section.
33    fn acquire() -> Self::State;
34
35    /// Leaves the critical section.
36    fn release(state: Self::State);
37}
38
39/// Raw state which does not alter the execution context.
40#[doc(hidden)]
41pub struct RawState;
42
43/// State which disables kernel preemption.
44#[doc(hidden)]
45pub struct PreemptState;
46
47/// State which saves and disables local interrupts.
48#[doc(hidden)]
49pub struct IrqSaveState;
50
51/// State which disables preemption, then saves and disables interrupts.
52#[doc(hidden)]
53pub struct PreemptIrqSaveState;
54
55impl GuardState for RawState {
56    type State = usize;
57
58    fn acquire() -> Self::State {
59        crate::interface::context_enter(CONTEXT_RAW)
60    }
61
62    fn release(state: Self::State) {
63        crate::interface::context_exit(CONTEXT_RAW, state);
64    }
65}
66
67impl GuardState for PreemptState {
68    type State = usize;
69
70    fn acquire() -> Self::State {
71        crate::interface::context_enter(CONTEXT_PREEMPT)
72    }
73
74    fn release(state: Self::State) {
75        crate::interface::context_exit(CONTEXT_PREEMPT, state);
76    }
77}
78
79impl GuardState for IrqSaveState {
80    type State = usize;
81
82    fn acquire() -> Self::State {
83        crate::interface::context_enter(CONTEXT_IRQSAVE)
84    }
85
86    fn release(state: Self::State) {
87        crate::interface::context_exit(CONTEXT_IRQSAVE, state);
88    }
89}
90
91impl GuardState for PreemptIrqSaveState {
92    type State = usize;
93
94    fn acquire() -> Self::State {
95        crate::interface::context_enter(CONTEXT_PREEMPT_IRQSAVE)
96    }
97
98    fn release(state: Self::State) {
99        crate::interface::context_exit(CONTEXT_PREEMPT_IRQSAVE, state);
100    }
101}
102
103/// An RAII guard which disables kernel preemption while it is alive.
104///
105/// ```compile_fail
106/// fn require_send<T: Send>() {}
107/// require_send::<ax_sync::PreemptGuard>();
108/// ```
109pub struct PreemptGuard {
110    state: Option<usize>,
111    _not_send: PhantomData<*mut ()>,
112}
113
114impl PreemptGuard {
115    /// Disables preemption until the returned guard is dropped.
116    pub fn new() -> Self {
117        Self {
118            state: Some(PreemptState::acquire()),
119            _not_send: PhantomData,
120        }
121    }
122
123    /// Finishes this preemption scope at the final IRQ-return boundary.
124    #[doc(hidden)]
125    pub fn finish_irq_return(mut self) {
126        let state = self
127            .state
128            .take()
129            .expect("IRQ-return preemption state must be present");
130        crate::interface::preempt_exit_from_irq_return(state);
131    }
132}
133
134impl Default for PreemptGuard {
135    fn default() -> Self {
136        Self::new()
137    }
138}
139
140impl Drop for PreemptGuard {
141    fn drop(&mut self) {
142        if let Some(state) = self.state.take() {
143            PreemptState::release(state);
144        }
145    }
146}
147
148/// An RAII guard which saves and disables local interrupts.
149///
150/// ```compile_fail
151/// fn require_send<T: Send>() {}
152/// require_send::<ax_sync::IrqSaveGuard>();
153/// ```
154pub struct IrqSaveGuard {
155    state: usize,
156    _not_send: PhantomData<*mut ()>,
157}
158
159impl IrqSaveGuard {
160    /// Saves and disables local interrupts until drop.
161    pub fn new() -> Self {
162        Self {
163            state: IrqSaveState::acquire(),
164            _not_send: PhantomData,
165        }
166    }
167}
168
169impl Default for IrqSaveGuard {
170    fn default() -> Self {
171        Self::new()
172    }
173}
174
175impl Drop for IrqSaveGuard {
176    fn drop(&mut self) {
177        IrqSaveState::release(self.state);
178    }
179}
180
181/// An RAII guard which disables preemption and local interrupts.
182///
183/// Entry disables preemption before interrupts. Drop restores interrupts
184/// before re-enabling preemption.
185///
186/// ```compile_fail
187/// fn require_send<T: Send>() {}
188/// require_send::<ax_sync::PreemptIrqSaveGuard>();
189/// ```
190pub struct PreemptIrqSaveGuard {
191    state: usize,
192    _not_send: PhantomData<*mut ()>,
193}
194
195impl PreemptIrqSaveGuard {
196    /// Enters a preemption-disabled, IRQ-disabled critical section.
197    pub fn new() -> Self {
198        Self {
199            state: PreemptIrqSaveState::acquire(),
200            _not_send: PhantomData,
201        }
202    }
203}
204
205impl Default for PreemptIrqSaveGuard {
206    fn default() -> Self {
207        Self::new()
208    }
209}
210
211impl Drop for PreemptIrqSaveGuard {
212    fn drop(&mut self) {
213        PreemptIrqSaveState::release(self.state);
214    }
215}