1use 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 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 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 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
103pub 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
184pub 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
211pub 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 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#[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#[inline(always)]
266pub fn hardirq_enter() {
267 task_runtime::hardirq_enter();
268}
269
270#[inline(always)]
272pub fn hardirq_exit() {
273 task_runtime::hardirq_exit();
274}
275
276pub 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}