Skip to main content

ax_task/sync/
context.rs

1//! Task-owned execution-context guards for synchronization primitives.
2
3use core::marker::PhantomData;
4
5use crate::runtime::{
6    PreemptGuardSource,
7    cpu::{LocalIrqState, PreemptGuardToken},
8    enter_preempt_guard, task_runtime,
9};
10
11pub(crate) trait ContextBackend {
12    type PreemptState: Copy;
13    type IrqState: Copy;
14
15    fn preempt_enter(&self) -> Self::PreemptState;
16    fn preempt_exit(&self, state: Self::PreemptState);
17    fn preempt_exit_irq_return(&self, state: Self::PreemptState);
18    fn irq_save_and_disable(&self) -> Self::IrqState;
19    fn irq_restore(&self, state: Self::IrqState);
20}
21
22pub(crate) struct TaskRuntimeContext;
23
24impl ContextBackend for TaskRuntimeContext {
25    type PreemptState = PreemptGuardToken;
26    type IrqState = LocalIrqState;
27
28    fn preempt_enter(&self) -> Self::PreemptState {
29        enter_preempt_guard(PreemptGuardSource::SyncContext)
30    }
31
32    fn preempt_exit(&self, state: Self::PreemptState) {
33        if state.is_none() {
34            return;
35        }
36        // SAFETY: the matching acquire returned this same-context token.
37        unsafe { task_runtime::preempt_guard_exit(state) };
38    }
39
40    fn preempt_exit_irq_return(&self, state: Self::PreemptState) {
41        if state.is_none() {
42            return;
43        }
44        // SAFETY: the matching acquire returned this token, and IRQ-return
45        // consumes it while the raw local-IRQ guard remains active.
46        unsafe { task_runtime::preempt_guard_exit_irq_return(state) };
47    }
48
49    fn irq_save_and_disable(&self) -> Self::IrqState {
50        task_runtime::local_irq_save_and_disable()
51    }
52
53    fn irq_restore(&self, state: Self::IrqState) {
54        // SAFETY: the matching acquire returned this raw state on this CPU.
55        unsafe { task_runtime::local_irq_restore(state) };
56    }
57}
58
59struct PendingPreempt<'backend, B: ContextBackend> {
60    backend: &'backend B,
61    state: Option<B::PreemptState>,
62}
63
64impl<'backend, B: ContextBackend> PendingPreempt<'backend, B> {
65    fn acquire(backend: &'backend B) -> Self {
66        Self {
67            backend,
68            state: Some(backend.preempt_enter()),
69        }
70    }
71
72    fn into_state(mut self) -> B::PreemptState {
73        self.state
74            .take()
75            .expect("pending preemption state must be owned")
76    }
77}
78
79impl<B: ContextBackend> Drop for PendingPreempt<'_, B> {
80    fn drop(&mut self) {
81        if let Some(state) = self.state.take() {
82            self.backend.preempt_exit(state);
83        }
84    }
85}
86
87pub(crate) fn enter_preempt_irqsave<B: ContextBackend>(
88    backend: &B,
89) -> (B::PreemptState, B::IrqState) {
90    let preempt = PendingPreempt::acquire(backend);
91    let irq = backend.irq_save_and_disable();
92    (preempt.into_state(), irq)
93}
94
95pub(crate) fn exit_preempt_irqsave<B: ContextBackend>(
96    (preempt, irq): (B::PreemptState, B::IrqState),
97    backend: &B,
98) {
99    backend.irq_restore(irq);
100    backend.preempt_exit(preempt);
101}
102
103/// Internal critical-section contract shared by task-owned lock algorithms.
104pub trait GuardState {
105    type State: Copy;
106
107    fn acquire() -> Self::State;
108
109    fn release(state: Self::State);
110
111    #[cfg(feature = "lockdep")]
112    fn lockdep_enabled() -> bool {
113        false
114    }
115}
116
117pub struct RawState;
118pub struct PreemptState;
119pub struct IrqSaveState;
120pub struct PreemptIrqSaveState;
121
122impl GuardState for RawState {
123    type State = ();
124
125    #[inline(always)]
126    fn acquire() -> Self::State {}
127
128    #[inline(always)]
129    fn release(_state: Self::State) {}
130}
131
132impl GuardState for PreemptState {
133    type State = PreemptGuardToken;
134
135    #[inline(always)]
136    fn acquire() -> Self::State {
137        TaskRuntimeContext.preempt_enter()
138    }
139
140    #[inline(always)]
141    fn release(state: Self::State) {
142        TaskRuntimeContext.preempt_exit(state);
143    }
144
145    #[cfg(feature = "lockdep")]
146    fn lockdep_enabled() -> bool {
147        true
148    }
149}
150
151impl GuardState for IrqSaveState {
152    type State = LocalIrqState;
153
154    #[inline(always)]
155    fn acquire() -> Self::State {
156        TaskRuntimeContext.irq_save_and_disable()
157    }
158
159    #[inline(always)]
160    fn release(state: Self::State) {
161        TaskRuntimeContext.irq_restore(state);
162    }
163}
164
165impl GuardState for PreemptIrqSaveState {
166    type State = (PreemptGuardToken, LocalIrqState);
167
168    #[inline(always)]
169    fn acquire() -> Self::State {
170        enter_preempt_irqsave(&TaskRuntimeContext)
171    }
172
173    #[inline(always)]
174    fn release((preempt, irq): Self::State) {
175        exit_preempt_irqsave((preempt, irq), &TaskRuntimeContext);
176    }
177
178    #[cfg(feature = "lockdep")]
179    fn lockdep_enabled() -> bool {
180        true
181    }
182}
183
184/// An RAII guard which disables kernel preemption while it is alive.
185pub struct PreemptGuard {
186    state: <PreemptState as GuardState>::State,
187    _not_send: PhantomData<*mut ()>,
188}
189
190impl PreemptGuard {
191    pub fn new() -> Self {
192        Self {
193            state: PreemptState::acquire(),
194            _not_send: PhantomData,
195        }
196    }
197}
198
199impl Default for PreemptGuard {
200    fn default() -> Self {
201        Self::new()
202    }
203}
204
205impl Drop for PreemptGuard {
206    fn drop(&mut self) {
207        PreemptState::release(self.state);
208    }
209}
210
211/// An RAII guard which saves and disables local interrupts while it is alive.
212pub struct IrqSaveGuard {
213    state: <IrqSaveState as GuardState>::State,
214    _not_send: PhantomData<*mut ()>,
215}
216
217impl IrqSaveGuard {
218    pub fn new() -> Self {
219        Self {
220            state: IrqSaveState::acquire(),
221            _not_send: PhantomData,
222        }
223    }
224
225    /// Disables preemption for work completed by a hard-IRQ return epilogue.
226    ///
227    /// The mutable borrow prevents raw local-IRQ restoration before the
228    /// dedicated preemption exit has completed.
229    pub fn disable_preempt_for_irq_return(&mut self) -> IrqReturnPreemptGuard<'_> {
230        IrqReturnPreemptGuard {
231            token: enter_preempt_guard(PreemptGuardSource::IrqReturn),
232            _irq_guard: PhantomData,
233            _not_send: PhantomData,
234        }
235    }
236}
237
238impl Default for IrqSaveGuard {
239    fn default() -> Self {
240        Self::new()
241    }
242}
243
244impl Drop for IrqSaveGuard {
245    fn drop(&mut self) {
246        IrqSaveState::release(self.state);
247    }
248}
249
250/// A preemption guard whose final release is an explicit IRQ-return boundary.
251#[must_use = "dropping the guard completes the IRQ-return preemption exit"]
252pub struct IrqReturnPreemptGuard<'irq> {
253    token: PreemptGuardToken,
254    _irq_guard: PhantomData<&'irq mut IrqSaveGuard>,
255    _not_send: PhantomData<*mut ()>,
256}
257
258impl Drop for IrqReturnPreemptGuard<'_> {
259    fn drop(&mut self) {
260        TaskRuntimeContext.preempt_exit_irq_return(self.token);
261    }
262}
263
264/// Publishes entry into the runtime's hard-interrupt lifecycle.
265#[inline(always)]
266pub fn hardirq_enter() {
267    task_runtime::hardirq_enter();
268}
269
270/// Publishes exit from the runtime's hard-interrupt lifecycle.
271#[inline(always)]
272pub fn hardirq_exit() {
273    task_runtime::hardirq_exit();
274}
275
276/// An RAII guard which disables preemption and local interrupts.
277///
278/// Entry disables preemption before interrupts. Drop restores interrupts
279/// before re-enabling preemption, matching Linux spin-lock IRQ-save ordering.
280pub struct PreemptIrqSaveGuard {
281    state: <PreemptIrqSaveState as GuardState>::State,
282    _not_send: PhantomData<*mut ()>,
283}
284
285impl PreemptIrqSaveGuard {
286    pub fn new() -> Self {
287        Self {
288            state: PreemptIrqSaveState::acquire(),
289            _not_send: PhantomData,
290        }
291    }
292}
293
294impl Default for PreemptIrqSaveGuard {
295    fn default() -> Self {
296        Self::new()
297    }
298}
299
300impl Drop for PreemptIrqSaveGuard {
301    fn drop(&mut self) {
302        PreemptIrqSaveState::release(self.state);
303    }
304}