1mod base;
4#[cfg(feature = "lockdep")]
5pub(crate) mod lockdep;
6#[cfg(feature = "lock-api")]
7mod raw;
8pub(crate) mod rwlock;
9
10use core::{fmt, ptr};
11
12#[cfg(feature = "lock-api")]
13pub use self::raw::*;
14use self::{
15 base::{BaseSpinLock, BaseSpinLockGuard},
16 rwlock::{BaseSpinRwLock, BaseSpinRwLockReadGuard, BaseSpinRwLockWriteGuard},
17};
18use crate::sync::context::{PreemptIrqSaveState, PreemptState, RawState};
19
20#[repr(transparent)]
26pub struct SpinLock<T: ?Sized>(BaseSpinLock<RawState, T>);
27
28pub type SpinLockGuard<'a, T> = BaseSpinLockGuard<'a, PreemptState, T>;
35
36pub type SpinLockIrqSaveGuard<'a, T> = BaseSpinLockGuard<'a, PreemptIrqSaveState, T>;
38
39pub type RawSpinLockGuard<'a, T> = BaseSpinLockGuard<'a, RawState, T>;
41
42impl<T> SpinLock<T> {
43 #[inline(always)]
45 #[track_caller]
46 pub const fn new(data: T) -> Self {
47 Self(BaseSpinLock::new(data))
48 }
49
50 #[inline(always)]
52 pub fn into_inner(self) -> T {
53 self.0.into_inner()
54 }
55}
56
57impl<T: ?Sized> SpinLock<T> {
58 #[inline(always)]
59 fn with_state<G: crate::sync::context::GuardState>(&self) -> &BaseSpinLock<G, T> {
60 unsafe { &*(ptr::from_ref(&self.0) as *const BaseSpinLock<G, T>) }
65 }
66
67 #[inline(always)]
68 fn with_state_mut<G: crate::sync::context::GuardState>(&mut self) -> &mut BaseSpinLock<G, T> {
69 unsafe { &mut *(ptr::from_mut(&mut self.0) as *mut BaseSpinLock<G, T>) }
71 }
72
73 #[inline(always)]
75 #[track_caller]
76 pub fn lock(&self) -> SpinLockGuard<'_, T> {
77 self.with_state::<PreemptState>().lock()
78 }
79
80 #[inline(always)]
85 #[track_caller]
86 pub fn lock_nested(&self, subclass: u32) -> SpinLockGuard<'_, T> {
87 self.with_state::<PreemptState>().lock_nested(subclass)
88 }
89
90 #[inline(always)]
92 #[track_caller]
93 pub fn try_lock(&self) -> Option<SpinLockGuard<'_, T>> {
94 self.with_state::<PreemptState>().try_lock()
95 }
96
97 #[inline(always)]
99 #[track_caller]
100 pub fn lock_irqsave(&self) -> SpinLockIrqSaveGuard<'_, T> {
101 self.with_state::<PreemptIrqSaveState>().lock()
102 }
103
104 #[inline(always)]
110 #[track_caller]
111 pub fn lock_irqsave_nested(&self, subclass: u32) -> SpinLockIrqSaveGuard<'_, T> {
112 self.with_state::<PreemptIrqSaveState>()
113 .lock_nested(subclass)
114 }
115
116 #[inline(always)]
118 #[track_caller]
119 pub fn try_lock_irqsave(&self) -> Option<SpinLockIrqSaveGuard<'_, T>> {
120 self.with_state::<PreemptIrqSaveState>().try_lock()
121 }
122
123 #[inline(always)]
131 #[track_caller]
132 pub unsafe fn lock_raw(&self) -> RawSpinLockGuard<'_, T> {
133 self.with_state::<RawState>().lock()
134 }
135
136 #[inline(always)]
143 #[track_caller]
144 pub unsafe fn try_lock_raw(&self) -> Option<RawSpinLockGuard<'_, T>> {
145 self.with_state::<RawState>().try_lock()
146 }
147
148 #[inline(always)]
152 pub fn is_locked(&self) -> bool {
153 self.0.is_locked()
154 }
155
156 #[inline(always)]
158 pub fn get_mut(&mut self) -> &mut T {
159 self.with_state_mut::<RawState>().get_mut()
160 }
161
162 #[doc(hidden)]
169 #[inline(always)]
170 pub unsafe fn force_unlock(&self) {
171 unsafe { self.with_state::<PreemptState>().force_unlock() };
172 }
173}
174
175impl<T: Default> Default for SpinLock<T> {
176 fn default() -> Self {
177 Self::new(T::default())
178 }
179}
180
181impl<T: fmt::Debug> fmt::Debug for SpinLock<T> {
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 match self.try_lock() {
184 Some(guard) => f.debug_struct("SpinLock").field("data", &&*guard).finish(),
185 None => f
186 .debug_struct("SpinLock")
187 .field("data", &"<locked>")
188 .finish(),
189 }
190 }
191}
192
193#[repr(transparent)]
195pub struct SpinRwLock<T: ?Sized>(BaseSpinRwLock<RawState, T>);
196
197pub type SpinRwLockReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptState, T>;
204
205pub type SpinRwLockWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, PreemptState, T>;
212
213pub type SpinRwLockIrqSaveReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, PreemptIrqSaveState, T>;
215
216pub type SpinRwLockIrqSaveWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, PreemptIrqSaveState, T>;
218
219pub type RawSpinRwLockReadGuard<'a, T> = BaseSpinRwLockReadGuard<'a, RawState, T>;
221
222pub type RawSpinRwLockWriteGuard<'a, T> = BaseSpinRwLockWriteGuard<'a, RawState, T>;
224
225impl<T> SpinRwLock<T> {
226 #[inline(always)]
228 #[track_caller]
229 pub const fn new(data: T) -> Self {
230 Self(BaseSpinRwLock::new(data))
231 }
232
233 #[inline(always)]
235 pub fn into_inner(self) -> T {
236 self.0.into_inner()
237 }
238}
239
240impl<T: ?Sized> SpinRwLock<T> {
241 #[inline(always)]
242 fn with_state<G: crate::sync::context::GuardState>(&self) -> &BaseSpinRwLock<G, T> {
243 unsafe { &*(ptr::from_ref(&self.0) as *const BaseSpinRwLock<G, T>) }
246 }
247
248 #[inline(always)]
249 fn with_state_mut<G: crate::sync::context::GuardState>(&mut self) -> &mut BaseSpinRwLock<G, T> {
250 unsafe { &mut *(ptr::from_mut(&mut self.0) as *mut BaseSpinRwLock<G, T>) }
252 }
253
254 #[inline(always)]
256 #[track_caller]
257 pub fn read(&self) -> SpinRwLockReadGuard<'_, T> {
258 self.with_state::<PreemptState>().read()
259 }
260
261 #[inline(always)]
263 #[track_caller]
264 pub fn try_read(&self) -> Option<SpinRwLockReadGuard<'_, T>> {
265 self.with_state::<PreemptState>().try_read()
266 }
267
268 #[inline(always)]
270 #[track_caller]
271 pub fn write(&self) -> SpinRwLockWriteGuard<'_, T> {
272 self.with_state::<PreemptState>().write()
273 }
274
275 #[inline(always)]
277 #[track_caller]
278 pub fn try_write(&self) -> Option<SpinRwLockWriteGuard<'_, T>> {
279 self.with_state::<PreemptState>().try_write()
280 }
281
282 #[inline(always)]
284 #[track_caller]
285 pub fn read_irqsave(&self) -> SpinRwLockIrqSaveReadGuard<'_, T> {
286 self.with_state::<PreemptIrqSaveState>().read()
287 }
288
289 #[inline(always)]
291 #[track_caller]
292 pub fn try_read_irqsave(&self) -> Option<SpinRwLockIrqSaveReadGuard<'_, T>> {
293 self.with_state::<PreemptIrqSaveState>().try_read()
294 }
295
296 #[inline(always)]
298 #[track_caller]
299 pub fn write_irqsave(&self) -> SpinRwLockIrqSaveWriteGuard<'_, T> {
300 self.with_state::<PreemptIrqSaveState>().write()
301 }
302
303 #[inline(always)]
305 #[track_caller]
306 pub fn try_write_irqsave(&self) -> Option<SpinRwLockIrqSaveWriteGuard<'_, T>> {
307 self.with_state::<PreemptIrqSaveState>().try_write()
308 }
309
310 #[inline(always)]
317 #[track_caller]
318 pub unsafe fn read_raw(&self) -> RawSpinRwLockReadGuard<'_, T> {
319 self.with_state::<RawState>().read()
320 }
321
322 #[inline(always)]
328 #[track_caller]
329 pub unsafe fn try_read_raw(&self) -> Option<RawSpinRwLockReadGuard<'_, T>> {
330 self.with_state::<RawState>().try_read()
331 }
332
333 #[inline(always)]
340 #[track_caller]
341 pub unsafe fn write_raw(&self) -> RawSpinRwLockWriteGuard<'_, T> {
342 self.with_state::<RawState>().write()
343 }
344
345 #[inline(always)]
351 #[track_caller]
352 pub unsafe fn try_write_raw(&self) -> Option<RawSpinRwLockWriteGuard<'_, T>> {
353 self.with_state::<RawState>().try_write()
354 }
355
356 #[inline(always)]
358 pub fn get_mut(&mut self) -> &mut T {
359 self.with_state_mut::<RawState>().get_mut()
360 }
361
362 #[doc(hidden)]
369 #[inline(always)]
370 pub unsafe fn force_read_decrement_raw(&self) {
371 unsafe {
372 self.with_state::<RawState>().force_read_decrement();
373 }
374 }
375}
376
377impl<T: Default> Default for SpinRwLock<T> {
378 fn default() -> Self {
379 Self::new(T::default())
380 }
381}
382
383impl<T> From<T> for SpinRwLock<T> {
384 fn from(value: T) -> Self {
385 Self::new(value)
386 }
387}
388
389impl<T: fmt::Debug> fmt::Debug for SpinRwLock<T> {
390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391 match self.try_read() {
392 Some(guard) => f
393 .debug_struct("SpinRwLock")
394 .field("data", &&*guard)
395 .finish(),
396 None => f
397 .debug_struct("SpinRwLock")
398 .field("data", &"<write locked>")
399 .finish(),
400 }
401 }
402}
403
404#[cfg(all(test, feature = "host-test", not(target_os = "none")))]
405mod tests {
406 use std::{
407 sync::{Arc, mpsc},
408 thread,
409 };
410
411 use super::{SpinLock, SpinRwLock};
412 use crate::sync::context::host_context_snapshot;
413
414 #[test]
415 fn spin_lock_acquisition_method_selects_context_policy() {
416 let lock = SpinLock::new(());
417 assert_eq!(host_context_snapshot(), (0, true));
418
419 let guard = lock.lock();
420 assert_eq!(host_context_snapshot(), (1, true));
421 drop(guard);
422 assert_eq!(host_context_snapshot(), (0, true));
423
424 let guard = lock.lock_irqsave();
425 assert_eq!(host_context_snapshot(), (1, false));
426 drop(guard);
427 assert_eq!(host_context_snapshot(), (0, true));
428
429 let guard = lock.lock_irqsave_nested(1);
430 assert_eq!(host_context_snapshot(), (1, false));
431 drop(guard);
432 assert_eq!(host_context_snapshot(), (0, true));
433 }
434
435 #[test]
436 fn spin_rwlock_acquisition_method_selects_context_policy() {
437 let lock = SpinRwLock::new(());
438
439 let reader = lock.read();
440 assert_eq!(host_context_snapshot(), (1, true));
441 drop(reader);
442 assert_eq!(host_context_snapshot(), (0, true));
443
444 let writer = lock.write_irqsave();
445 assert_eq!(host_context_snapshot(), (1, false));
446 drop(writer);
447 assert_eq!(host_context_snapshot(), (0, true));
448 }
449
450 #[test]
451 fn failed_spin_rwlock_try_modes_restore_context() {
452 let lock = Arc::new(SpinRwLock::new(()));
453 let holder_lock = Arc::clone(&lock);
454 let (held_sender, held_receiver) = mpsc::channel();
455 let (release_sender, release_receiver) = mpsc::channel();
456 let holder = thread::spawn(move || {
457 let held = unsafe { holder_lock.write_raw() };
460 held_sender.send(()).unwrap();
461 release_receiver.recv().unwrap();
462 drop(held);
463 });
464 held_receiver.recv().unwrap();
465
466 assert!(lock.try_read().is_none());
467 assert_eq!(host_context_snapshot(), (0, true));
468 assert!(lock.try_write().is_none());
469 assert_eq!(host_context_snapshot(), (0, true));
470 assert!(lock.try_read_irqsave().is_none());
471 assert_eq!(host_context_snapshot(), (0, true));
472 assert!(lock.try_write_irqsave().is_none());
473 assert_eq!(host_context_snapshot(), (0, true));
474 assert!(unsafe { lock.try_read_raw() }.is_none());
475 assert!(unsafe { lock.try_write_raw() }.is_none());
476 assert_eq!(host_context_snapshot(), (0, true));
477
478 release_sender.send(()).unwrap();
479 holder.join().unwrap();
480 }
481}