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 RawSpinLock<T: ?Sized>(BaseSpinLock<RawState, T>);
27
28/// A guard returned by [`RawSpinLock::lock`].
29pub type RawSpinLockGuard<'a, T> = BaseSpinLockGuard<'a, PreemptState, T>;
30
31/// A guard returned by [`RawSpinLock::lock_irqsave`].
32pub type RawSpinLockIrqSaveGuard<'a, T> = BaseSpinLockGuard<'a, PreemptIrqSaveState, T>;
33
34/// A guard returned by [`RawSpinLock::lock_raw`].
35pub type RawSpinLockUnpinnedGuard<'a, T> = BaseSpinLockGuard<'a, RawState, T>;
36
37impl<T> RawSpinLock<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> RawSpinLock<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) -> RawSpinLockGuard<'_, 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) -> RawSpinLockGuard<'_, 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<RawSpinLockGuard<'_, 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) -> RawSpinLockIrqSaveGuard<'_, 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) -> RawSpinLockIrqSaveGuard<'_, 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<RawSpinLockIrqSaveGuard<'_, 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) -> RawSpinLockUnpinnedGuard<'_, 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<RawSpinLockUnpinnedGuard<'_, 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 RawSpinLock<T> {
171    fn default() -> Self {
172        Self::new(T::default())
173    }
174}
175
176impl<T: fmt::Debug> fmt::Debug for RawSpinLock<T> {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        match self.try_lock() {
179            Some(guard) => f
180                .debug_struct("RawSpinLock")
181                .field("data", &&*guard)
182                .finish(),
183            None => f
184                .debug_struct("RawSpinLock")
185                .field("data", &"<locked>")
186                .finish(),
187        }
188    }
189}
190
191/// A non-sleeping read-write lock with acquisition-site context policy.
192#[repr(transparent)]
193pub struct RawSpinRwLock<T: ?Sized>(BaseSpinRwLock<RawState, T>);
194
195/// A read guard returned by [`RawSpinRwLock::read`].
196pub type RawSpinRwLockReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptState, T>;
197
198/// A write guard returned by [`RawSpinRwLock::write`].
199pub type RawSpinRwLockWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, PreemptState, T>;
200
201/// An IRQ-save read guard.
202pub type RawSpinRwLockIrqSaveReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptIrqSaveState, T>;
203
204/// An IRQ-save write guard.
205pub type RawSpinRwLockIrqSaveWriteGuard<'a, T> =
206    BaseSpinRwLockWriteGuard<'a, PreemptIrqSaveState, T>;
207
208/// A raw read guard.
209pub type RawSpinRwLockUnpinnedReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, RawState, T>;
210
211/// A raw write guard.
212pub type RawSpinRwLockUnpinnedWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, RawState, T>;
213
214impl<T> RawSpinRwLock<T> {
215    /// Creates an unlocked spin read-write lock.
216    #[inline(always)]
217    #[track_caller]
218    pub const fn new(data: T) -> Self {
219        Self(BaseSpinRwLock::new(data))
220    }
221
222    /// Consumes the lock and returns the protected value.
223    #[inline(always)]
224    pub fn into_inner(self) -> T {
225        self.0.into_inner()
226    }
227}
228
229impl<T: ?Sized> RawSpinRwLock<T> {
230    #[inline(always)]
231    fn with_state<G: GuardState>(&self) -> &BaseSpinRwLock<G, T> {
232        // SAFETY: identical to `RawSpinLock::with_state`; the generic parameter
233        // is represented only by `PhantomData` in a stable C layout.
234        unsafe { &*(ptr::from_ref(&self.0) as *const BaseSpinRwLock<G, T>) }
235    }
236
237    #[inline(always)]
238    fn with_state_mut<G: GuardState>(&mut self) -> &mut BaseSpinRwLock<G, T> {
239        // SAFETY: see `with_state`; the exclusive borrow prevents aliases.
240        unsafe { &mut *(ptr::from_mut(&mut self.0) as *mut BaseSpinRwLock<G, T>) }
241    }
242
243    /// Acquires a read guard after disabling preemption.
244    #[inline(always)]
245    #[track_caller]
246    pub fn read(&self) -> RawSpinRwLockReadGuard<'_, T> {
247        self.with_state::<PreemptState>().read()
248    }
249
250    /// Attempts a read acquisition after disabling preemption.
251    #[inline(always)]
252    #[track_caller]
253    pub fn try_read(&self) -> Option<RawSpinRwLockReadGuard<'_, T>> {
254        self.with_state::<PreemptState>().try_read()
255    }
256
257    /// Acquires a write guard after disabling preemption.
258    #[inline(always)]
259    #[track_caller]
260    pub fn write(&self) -> RawSpinRwLockWriteGuard<'_, T> {
261        self.with_state::<PreemptState>().write()
262    }
263
264    /// Attempts a write acquisition after disabling preemption.
265    #[inline(always)]
266    #[track_caller]
267    pub fn try_write(&self) -> Option<RawSpinRwLockWriteGuard<'_, T>> {
268        self.with_state::<PreemptState>().try_write()
269    }
270
271    /// Acquires an IRQ-save read guard.
272    #[inline(always)]
273    #[track_caller]
274    pub fn read_irqsave(&self) -> RawSpinRwLockIrqSaveReadGuard<'_, T> {
275        self.with_state::<PreemptIrqSaveState>().read()
276    }
277
278    /// Attempts an IRQ-save read acquisition.
279    #[inline(always)]
280    #[track_caller]
281    pub fn try_read_irqsave(&self) -> Option<RawSpinRwLockIrqSaveReadGuard<'_, T>> {
282        self.with_state::<PreemptIrqSaveState>().try_read()
283    }
284
285    /// Acquires an IRQ-save write guard.
286    #[inline(always)]
287    #[track_caller]
288    pub fn write_irqsave(&self) -> RawSpinRwLockIrqSaveWriteGuard<'_, T> {
289        self.with_state::<PreemptIrqSaveState>().write()
290    }
291
292    /// Attempts an IRQ-save write acquisition.
293    #[inline(always)]
294    #[track_caller]
295    pub fn try_write_irqsave(&self) -> Option<RawSpinRwLockIrqSaveWriteGuard<'_, T>> {
296        self.with_state::<PreemptIrqSaveState>().try_write()
297    }
298
299    /// Acquires a raw read guard without changing execution context.
300    ///
301    /// # Safety
302    ///
303    /// The caller must prevent re-entry and uphold the read-side exclusion
304    /// contract, including on single-core builds.
305    #[inline(always)]
306    #[track_caller]
307    pub unsafe fn read_raw(&self) -> RawSpinRwLockUnpinnedReadGuard<'_, T> {
308        self.with_state::<RawState>().read()
309    }
310
311    /// Attempts a raw read acquisition.
312    ///
313    /// # Safety
314    ///
315    /// The caller must uphold the contract of [`Self::read_raw`].
316    #[inline(always)]
317    #[track_caller]
318    pub unsafe fn try_read_raw(&self) -> Option<RawSpinRwLockUnpinnedReadGuard<'_, T>> {
319        self.with_state::<RawState>().try_read()
320    }
321
322    /// Acquires a raw write guard without changing execution context.
323    ///
324    /// # Safety
325    ///
326    /// The caller must prevent re-entry and concurrent readers or writers,
327    /// including on single-core builds.
328    #[inline(always)]
329    #[track_caller]
330    pub unsafe fn write_raw(&self) -> RawSpinRwLockUnpinnedWriteGuard<'_, T> {
331        self.with_state::<RawState>().write()
332    }
333
334    /// Attempts a raw write acquisition.
335    ///
336    /// # Safety
337    ///
338    /// The caller must uphold the contract of [`Self::write_raw`].
339    #[inline(always)]
340    #[track_caller]
341    pub unsafe fn try_write_raw(&self) -> Option<RawSpinRwLockUnpinnedWriteGuard<'_, T>> {
342        self.with_state::<RawState>().try_write()
343    }
344
345    /// Returns mutable access without locking.
346    #[inline(always)]
347    pub fn get_mut(&mut self) -> &mut T {
348        self.with_state_mut::<RawState>().get_mut()
349    }
350
351    /// Removes one deliberately leaked raw read guard from the reader count.
352    ///
353    /// # Safety
354    ///
355    /// The caller must own a deliberately forgotten guard returned by
356    /// [`Self::read_raw`] and must prove that no live reference from it remains.
357    #[doc(hidden)]
358    #[inline(always)]
359    pub unsafe fn force_read_decrement_raw(&self) {
360        unsafe {
361            self.with_state::<RawState>().force_read_decrement();
362        }
363    }
364}
365
366impl<T: Default> Default for RawSpinRwLock<T> {
367    fn default() -> Self {
368        Self::new(T::default())
369    }
370}
371
372impl<T> From<T> for RawSpinRwLock<T> {
373    fn from(value: T) -> Self {
374        Self::new(value)
375    }
376}
377
378impl<T: fmt::Debug> fmt::Debug for RawSpinRwLock<T> {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        match self.try_read() {
381            Some(guard) => f
382                .debug_struct("RawSpinRwLock")
383                .field("data", &&*guard)
384                .finish(),
385            None => f
386                .debug_struct("RawSpinRwLock")
387                .field("data", &"<write locked>")
388                .finish(),
389        }
390    }
391}