Skip to main content

ax_task/sync/spin/
mod.rs

1//! Public spin-lock types whose acquisition methods express context policy.
2
3use core::{fmt, ptr};
4
5use self::{
6    base::{BaseSpinLock, BaseSpinLockGuard},
7    rwlock::{BaseSpinRwLock, BaseSpinRwLockReadGuard, BaseSpinRwLockWriteGuard},
8};
9use super::context::{GuardState, PreemptIrqSaveState, PreemptState, RawState};
10
11pub(crate) mod atomic;
12mod base;
13#[cfg(feature = "lockdep")]
14pub(crate) mod lockdep;
15mod raw;
16mod rwlock;
17
18pub use self::raw::RawIrqSaveMutex;
19
20/// A non-sleeping mutual-exclusion lock.
21///
22/// The lock object does not bake in an execution-context policy. Callers
23/// choose the policy at the acquisition site with [`Self::lock`],
24/// [`Self::lock_irqsave`], or [`Self::lock_raw`].
25#[repr(transparent)]
26pub struct SpinLock<T: ?Sized>(BaseSpinLock<RawState, T>);
27
28/// A guard returned by [`SpinLock::lock`].
29pub type SpinLockGuard<'a, T> = BaseSpinLockGuard<'a, PreemptState, T>;
30
31/// A guard returned by [`SpinLock::lock_irqsave`].
32pub type SpinLockIrqSaveGuard<'a, T> = BaseSpinLockGuard<'a, PreemptIrqSaveState, T>;
33
34/// A guard returned by [`SpinLock::lock_raw`].
35pub type RawSpinLockGuard<'a, T> = BaseSpinLockGuard<'a, RawState, T>;
36
37impl<T> SpinLock<T> {
38    /// Creates an unlocked spin lock.
39    #[inline(always)]
40    #[track_caller]
41    pub const fn new(data: T) -> Self {
42        Self(BaseSpinLock::new(data))
43    }
44
45    /// Consumes the lock and returns the protected value.
46    #[inline(always)]
47    pub fn into_inner(self) -> T {
48        self.0.into_inner()
49    }
50}
51
52impl<T: ?Sized> SpinLock<T> {
53    #[inline(always)]
54    fn with_state<G: GuardState>(&self) -> &BaseSpinLock<G, T> {
55        // SAFETY: `BaseSpinLock` has a stable C layout, and its guard-state
56        // parameter is represented only by `PhantomData`. The atomic state,
57        // lockdep map, and protected value therefore have identical addresses
58        // for every `G`.
59        unsafe { &*(ptr::from_ref(&self.0) as *const BaseSpinLock<G, T>) }
60    }
61
62    #[inline(always)]
63    fn with_state_mut<G: GuardState>(&mut self) -> &mut BaseSpinLock<G, T> {
64        // SAFETY: see `with_state`; the exclusive borrow prevents aliases.
65        unsafe { &mut *(ptr::from_mut(&mut self.0) as *mut BaseSpinLock<G, T>) }
66    }
67
68    /// Acquires the lock after disabling kernel preemption.
69    #[inline(always)]
70    #[track_caller]
71    pub fn lock(&self) -> SpinLockGuard<'_, T> {
72        self.with_state::<PreemptState>().lock()
73    }
74
75    /// Acquires the lock after disabling preemption, using a lockdep subclass.
76    ///
77    /// This is intended for structurally nested acquisitions of different
78    /// locks with the same class. Without `lockdep`, `subclass` has no effect.
79    #[inline(always)]
80    #[track_caller]
81    pub fn lock_nested(&self, subclass: u32) -> SpinLockGuard<'_, T> {
82        self.with_state::<PreemptState>().lock_nested(subclass)
83    }
84
85    /// Attempts to acquire the lock after disabling kernel preemption.
86    #[inline(always)]
87    #[track_caller]
88    pub fn try_lock(&self) -> Option<SpinLockGuard<'_, T>> {
89        self.with_state::<PreemptState>().try_lock()
90    }
91
92    /// Acquires the lock after disabling preemption and saving/disabling IRQs.
93    #[inline(always)]
94    #[track_caller]
95    pub fn lock_irqsave(&self) -> SpinLockIrqSaveGuard<'_, T> {
96        self.with_state::<PreemptIrqSaveState>().lock()
97    }
98
99    /// Acquires the lock after disabling preemption and saving/disabling IRQs,
100    /// using a lockdep subclass.
101    ///
102    /// This is intended for structurally nested acquisitions of different
103    /// locks with the same class. Without `lockdep`, `subclass` has no effect.
104    #[inline(always)]
105    #[track_caller]
106    pub fn lock_irqsave_nested(&self, subclass: u32) -> SpinLockIrqSaveGuard<'_, T> {
107        self.with_state::<PreemptIrqSaveState>()
108            .lock_nested(subclass)
109    }
110
111    /// Attempts to acquire the lock after disabling preemption and IRQs.
112    #[inline(always)]
113    #[track_caller]
114    pub fn try_lock_irqsave(&self) -> Option<SpinLockIrqSaveGuard<'_, T>> {
115        self.with_state::<PreemptIrqSaveState>().try_lock()
116    }
117
118    /// Acquires the lock without changing preemption or interrupt state.
119    ///
120    /// # Safety
121    ///
122    /// The caller must prevent same-CPU re-entry and all concurrent access
123    /// which could violate exclusive access, including on single-core builds
124    /// where the atomic lock word is compiled out.
125    #[inline(always)]
126    #[track_caller]
127    pub unsafe fn lock_raw(&self) -> RawSpinLockGuard<'_, T> {
128        self.with_state::<RawState>().lock()
129    }
130
131    /// Attempts a raw acquisition without changing execution context.
132    ///
133    /// # Safety
134    ///
135    /// The caller must uphold the same exclusion contract as
136    /// [`Self::lock_raw`], even when this function returns `None`.
137    #[inline(always)]
138    #[track_caller]
139    pub unsafe fn try_lock_raw(&self) -> Option<RawSpinLockGuard<'_, T>> {
140        self.with_state::<RawState>().try_lock()
141    }
142
143    /// Returns whether the lock appears held.
144    ///
145    /// This is only a diagnostic snapshot and provides no synchronization.
146    #[inline(always)]
147    pub fn is_locked(&self) -> bool {
148        self.0.is_locked()
149    }
150
151    /// Returns mutable access without locking.
152    #[inline(always)]
153    pub fn get_mut(&mut self) -> &mut T {
154        self.with_state_mut::<RawState>().get_mut()
155    }
156
157    /// Releases a preemption-mode lock without consuming its guard.
158    ///
159    /// # Safety
160    ///
161    /// The caller must own exactly one guard returned by [`Self::lock`] and
162    /// must ensure that guard will never subsequently be dropped.
163    #[doc(hidden)]
164    #[inline(always)]
165    pub unsafe fn force_unlock(&self) {
166        unsafe { self.with_state::<PreemptState>().force_unlock() };
167    }
168}
169
170impl<T: Default> Default for SpinLock<T> {
171    fn default() -> Self {
172        Self::new(T::default())
173    }
174}
175
176impl<T: fmt::Debug> fmt::Debug for SpinLock<T> {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        match self.try_lock() {
179            Some(guard) => f.debug_struct("SpinLock").field("data", &&*guard).finish(),
180            None => f
181                .debug_struct("SpinLock")
182                .field("data", &"<locked>")
183                .finish(),
184        }
185    }
186}
187
188/// A non-sleeping read-write lock with acquisition-site context policy.
189#[repr(transparent)]
190pub struct SpinRwLock<T: ?Sized>(BaseSpinRwLock<RawState, T>);
191
192/// A read guard returned by [`SpinRwLock::read`].
193pub type SpinRwLockReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptState, T>;
194
195/// A write guard returned by [`SpinRwLock::write`].
196pub type SpinRwLockWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, PreemptState, T>;
197
198/// An IRQ-save read guard.
199pub type SpinRwLockIrqSaveReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptIrqSaveState, T>;
200
201/// An IRQ-save write guard.
202pub type SpinRwLockIrqSaveWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, PreemptIrqSaveState, T>;
203
204/// A raw read guard.
205pub type RawSpinRwLockReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, RawState, T>;
206
207/// A raw write guard.
208pub type RawSpinRwLockWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, RawState, T>;
209
210impl<T> SpinRwLock<T> {
211    /// Creates an unlocked spin read-write lock.
212    #[inline(always)]
213    #[track_caller]
214    pub const fn new(data: T) -> Self {
215        Self(BaseSpinRwLock::new(data))
216    }
217
218    /// Consumes the lock and returns the protected value.
219    #[inline(always)]
220    pub fn into_inner(self) -> T {
221        self.0.into_inner()
222    }
223}
224
225impl<T: ?Sized> SpinRwLock<T> {
226    #[inline(always)]
227    fn with_state<G: GuardState>(&self) -> &BaseSpinRwLock<G, T> {
228        // SAFETY: identical to `SpinLock::with_state`; the generic parameter
229        // is represented only by `PhantomData` in a stable C layout.
230        unsafe { &*(ptr::from_ref(&self.0) as *const BaseSpinRwLock<G, T>) }
231    }
232
233    #[inline(always)]
234    fn with_state_mut<G: GuardState>(&mut self) -> &mut BaseSpinRwLock<G, T> {
235        // SAFETY: see `with_state`; the exclusive borrow prevents aliases.
236        unsafe { &mut *(ptr::from_mut(&mut self.0) as *mut BaseSpinRwLock<G, T>) }
237    }
238
239    /// Acquires a read guard after disabling preemption.
240    #[inline(always)]
241    #[track_caller]
242    pub fn read(&self) -> SpinRwLockReadGuard<'_, T> {
243        self.with_state::<PreemptState>().read()
244    }
245
246    /// Attempts a read acquisition after disabling preemption.
247    #[inline(always)]
248    #[track_caller]
249    pub fn try_read(&self) -> Option<SpinRwLockReadGuard<'_, T>> {
250        self.with_state::<PreemptState>().try_read()
251    }
252
253    /// Acquires a write guard after disabling preemption.
254    #[inline(always)]
255    #[track_caller]
256    pub fn write(&self) -> SpinRwLockWriteGuard<'_, T> {
257        self.with_state::<PreemptState>().write()
258    }
259
260    /// Attempts a write acquisition after disabling preemption.
261    #[inline(always)]
262    #[track_caller]
263    pub fn try_write(&self) -> Option<SpinRwLockWriteGuard<'_, T>> {
264        self.with_state::<PreemptState>().try_write()
265    }
266
267    /// Acquires an IRQ-save read guard.
268    #[inline(always)]
269    #[track_caller]
270    pub fn read_irqsave(&self) -> SpinRwLockIrqSaveReadGuard<'_, T> {
271        self.with_state::<PreemptIrqSaveState>().read()
272    }
273
274    /// Attempts an IRQ-save read acquisition.
275    #[inline(always)]
276    #[track_caller]
277    pub fn try_read_irqsave(&self) -> Option<SpinRwLockIrqSaveReadGuard<'_, T>> {
278        self.with_state::<PreemptIrqSaveState>().try_read()
279    }
280
281    /// Acquires an IRQ-save write guard.
282    #[inline(always)]
283    #[track_caller]
284    pub fn write_irqsave(&self) -> SpinRwLockIrqSaveWriteGuard<'_, T> {
285        self.with_state::<PreemptIrqSaveState>().write()
286    }
287
288    /// Attempts an IRQ-save write acquisition.
289    #[inline(always)]
290    #[track_caller]
291    pub fn try_write_irqsave(&self) -> Option<SpinRwLockIrqSaveWriteGuard<'_, T>> {
292        self.with_state::<PreemptIrqSaveState>().try_write()
293    }
294
295    /// Acquires a raw read guard without changing execution context.
296    ///
297    /// # Safety
298    ///
299    /// The caller must prevent re-entry and uphold the read-side exclusion
300    /// contract, including on single-core builds.
301    #[inline(always)]
302    #[track_caller]
303    pub unsafe fn read_raw(&self) -> RawSpinRwLockReadGuard<'_, T> {
304        self.with_state::<RawState>().read()
305    }
306
307    /// Attempts a raw read acquisition.
308    ///
309    /// # Safety
310    ///
311    /// The caller must uphold the contract of [`Self::read_raw`].
312    #[inline(always)]
313    #[track_caller]
314    pub unsafe fn try_read_raw(&self) -> Option<RawSpinRwLockReadGuard<'_, T>> {
315        self.with_state::<RawState>().try_read()
316    }
317
318    /// Acquires a raw write guard without changing execution context.
319    ///
320    /// # Safety
321    ///
322    /// The caller must prevent re-entry and concurrent readers or writers,
323    /// including on single-core builds.
324    #[inline(always)]
325    #[track_caller]
326    pub unsafe fn write_raw(&self) -> RawSpinRwLockWriteGuard<'_, T> {
327        self.with_state::<RawState>().write()
328    }
329
330    /// Attempts a raw write acquisition.
331    ///
332    /// # Safety
333    ///
334    /// The caller must uphold the contract of [`Self::write_raw`].
335    #[inline(always)]
336    #[track_caller]
337    pub unsafe fn try_write_raw(&self) -> Option<RawSpinRwLockWriteGuard<'_, T>> {
338        self.with_state::<RawState>().try_write()
339    }
340
341    /// Returns mutable access without locking.
342    #[inline(always)]
343    pub fn get_mut(&mut self) -> &mut T {
344        self.with_state_mut::<RawState>().get_mut()
345    }
346
347    /// Removes one deliberately leaked raw read guard from the reader count.
348    ///
349    /// # Safety
350    ///
351    /// The caller must own a deliberately forgotten guard returned by
352    /// [`Self::read_raw`] and must prove that no live reference from it remains.
353    #[doc(hidden)]
354    #[inline(always)]
355    pub unsafe fn force_read_decrement_raw(&self) {
356        unsafe {
357            self.with_state::<RawState>().force_read_decrement();
358        }
359    }
360}
361
362impl<T: Default> Default for SpinRwLock<T> {
363    fn default() -> Self {
364        Self::new(T::default())
365    }
366}
367
368impl<T> From<T> for SpinRwLock<T> {
369    fn from(value: T) -> Self {
370        Self::new(value)
371    }
372}
373
374impl<T: fmt::Debug> fmt::Debug for SpinRwLock<T> {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        match self.try_read() {
377            Some(guard) => f
378                .debug_struct("SpinRwLock")
379                .field("data", &&*guard)
380                .finish(),
381            None => f
382                .debug_struct("SpinRwLock")
383                .field("data", &"<write locked>")
384                .finish(),
385        }
386    }
387}