Coverage Report

Created: 2025-10-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/spin-0.9.8/src/mutex/spin.rs
Line
Count
Source
1
//! A naïve spinning mutex.
2
//!
3
//! Waiting threads hammer an atomic variable until it becomes available. Best-case latency is low, but worst-case
4
//! latency is theoretically infinite.
5
6
use crate::{
7
    atomic::{AtomicBool, Ordering},
8
    RelaxStrategy, Spin,
9
};
10
use core::{
11
    cell::UnsafeCell,
12
    fmt,
13
    marker::PhantomData,
14
    mem::ManuallyDrop,
15
    ops::{Deref, DerefMut},
16
};
17
18
/// A [spin lock](https://en.m.wikipedia.org/wiki/Spinlock) providing mutually exclusive access to data.
19
///
20
/// # Example
21
///
22
/// ```
23
/// use spin;
24
///
25
/// let lock = spin::mutex::SpinMutex::<_>::new(0);
26
///
27
/// // Modify the data
28
/// *lock.lock() = 2;
29
///
30
/// // Read the data
31
/// let answer = *lock.lock();
32
/// assert_eq!(answer, 2);
33
/// ```
34
///
35
/// # Thread safety example
36
///
37
/// ```
38
/// use spin;
39
/// use std::sync::{Arc, Barrier};
40
///
41
/// let thread_count = 1000;
42
/// let spin_mutex = Arc::new(spin::mutex::SpinMutex::<_>::new(0));
43
///
44
/// // We use a barrier to ensure the readout happens after all writing
45
/// let barrier = Arc::new(Barrier::new(thread_count + 1));
46
///
47
/// # let mut ts = Vec::new();
48
/// for _ in (0..thread_count) {
49
///     let my_barrier = barrier.clone();
50
///     let my_lock = spin_mutex.clone();
51
/// # let t =
52
///     std::thread::spawn(move || {
53
///         let mut guard = my_lock.lock();
54
///         *guard += 1;
55
///
56
///         // Release the lock to prevent a deadlock
57
///         drop(guard);
58
///         my_barrier.wait();
59
///     });
60
/// # ts.push(t);
61
/// }
62
///
63
/// barrier.wait();
64
///
65
/// let answer = { *spin_mutex.lock() };
66
/// assert_eq!(answer, thread_count);
67
///
68
/// # for t in ts {
69
/// #     t.join().unwrap();
70
/// # }
71
/// ```
72
pub struct SpinMutex<T: ?Sized, R = Spin> {
73
    phantom: PhantomData<R>,
74
    pub(crate) lock: AtomicBool,
75
    data: UnsafeCell<T>,
76
}
77
78
/// A guard that provides mutable data access.
79
///
80
/// When the guard falls out of scope it will release the lock.
81
pub struct SpinMutexGuard<'a, T: ?Sized + 'a> {
82
    lock: &'a AtomicBool,
83
    data: *mut T,
84
}
85
86
// Same unsafe impls as `std::sync::Mutex`
87
unsafe impl<T: ?Sized + Send, R> Sync for SpinMutex<T, R> {}
88
unsafe impl<T: ?Sized + Send, R> Send for SpinMutex<T, R> {}
89
90
unsafe impl<T: ?Sized + Sync> Sync for SpinMutexGuard<'_, T> {}
91
unsafe impl<T: ?Sized + Send> Send for SpinMutexGuard<'_, T> {}
92
93
impl<T, R> SpinMutex<T, R> {
94
    /// Creates a new [`SpinMutex`] wrapping the supplied data.
95
    ///
96
    /// # Example
97
    ///
98
    /// ```
99
    /// use spin::mutex::SpinMutex;
100
    ///
101
    /// static MUTEX: SpinMutex<()> = SpinMutex::<_>::new(());
102
    ///
103
    /// fn demo() {
104
    ///     let lock = MUTEX.lock();
105
    ///     // do something with lock
106
    ///     drop(lock);
107
    /// }
108
    /// ```
109
    #[inline(always)]
110
0
    pub const fn new(data: T) -> Self {
111
0
        SpinMutex {
112
0
            lock: AtomicBool::new(false),
113
0
            data: UnsafeCell::new(data),
114
0
            phantom: PhantomData,
115
0
        }
116
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>::new
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<_, _>>::new
117
118
    /// Consumes this [`SpinMutex`] and unwraps the underlying data.
119
    ///
120
    /// # Example
121
    ///
122
    /// ```
123
    /// let lock = spin::mutex::SpinMutex::<_>::new(42);
124
    /// assert_eq!(42, lock.into_inner());
125
    /// ```
126
    #[inline(always)]
127
0
    pub fn into_inner(self) -> T {
128
        // We know statically that there are no outstanding references to
129
        // `self` so there's no need to lock.
130
0
        let SpinMutex { data, .. } = self;
131
0
        data.into_inner()
132
0
    }
133
134
    /// Returns a mutable pointer to the underlying data.
135
    ///
136
    /// This is mostly meant to be used for applications which require manual unlocking, but where
137
    /// storing both the lock and the pointer to the inner data gets inefficient.
138
    ///
139
    /// # Example
140
    /// ```
141
    /// let lock = spin::mutex::SpinMutex::<_>::new(42);
142
    ///
143
    /// unsafe {
144
    ///     core::mem::forget(lock.lock());
145
    ///
146
    ///     assert_eq!(lock.as_mut_ptr().read(), 42);
147
    ///     lock.as_mut_ptr().write(58);
148
    ///
149
    ///     lock.force_unlock();
150
    /// }
151
    ///
152
    /// assert_eq!(*lock.lock(), 58);
153
    ///
154
    /// ```
155
    #[inline(always)]
156
0
    pub fn as_mut_ptr(&self) -> *mut T {
157
0
        self.data.get()
158
0
    }
159
}
160
161
impl<T: ?Sized, R: RelaxStrategy> SpinMutex<T, R> {
162
    /// Locks the [`SpinMutex`] and returns a guard that permits access to the inner data.
163
    ///
164
    /// The returned value may be dereferenced for data access
165
    /// and the lock will be dropped when the guard falls out of scope.
166
    ///
167
    /// ```
168
    /// let lock = spin::mutex::SpinMutex::<_>::new(0);
169
    /// {
170
    ///     let mut data = lock.lock();
171
    ///     // The lock is now locked and the data can be accessed
172
    ///     *data += 1;
173
    ///     // The lock is implicitly dropped at the end of the scope
174
    /// }
175
    /// ```
176
    #[inline(always)]
177
0
    pub fn lock(&self) -> SpinMutexGuard<T> {
178
        // Can fail to lock even if the spinlock is not locked. May be more efficient than `try_lock`
179
        // when called in a loop.
180
0
        while self
181
0
            .lock
182
0
            .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
183
0
            .is_err()
184
        {
185
            // Wait until the lock looks unlocked before retrying
186
0
            while self.is_locked() {
187
0
                R::relax();
188
0
            }
189
        }
190
191
0
        SpinMutexGuard {
192
0
            lock: &self.lock,
193
0
            data: unsafe { &mut *self.data.get() },
194
0
        }
195
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>::lock
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<_, _>>::lock
196
}
197
198
impl<T: ?Sized, R> SpinMutex<T, R> {
199
    /// Returns `true` if the lock is currently held.
200
    ///
201
    /// # Safety
202
    ///
203
    /// This function provides no synchronization guarantees and so its result should be considered 'out of date'
204
    /// the instant it is called. Do not use it for synchronization purposes. However, it may be useful as a heuristic.
205
    #[inline(always)]
206
0
    pub fn is_locked(&self) -> bool {
207
0
        self.lock.load(Ordering::Relaxed)
208
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>>>::is_locked
Unexecuted instantiation: <spin::mutex::spin::SpinMutex<_, _>>::is_locked
209
210
    /// Force unlock this [`SpinMutex`].
211
    ///
212
    /// # Safety
213
    ///
214
    /// This is *extremely* unsafe if the lock is not held by the current
215
    /// thread. However, this can be useful in some instances for exposing the
216
    /// lock to FFI that doesn't know how to deal with RAII.
217
    #[inline(always)]
218
0
    pub unsafe fn force_unlock(&self) {
219
0
        self.lock.store(false, Ordering::Release);
220
0
    }
221
222
    /// Try to lock this [`SpinMutex`], returning a lock guard if successful.
223
    ///
224
    /// # Example
225
    ///
226
    /// ```
227
    /// let lock = spin::mutex::SpinMutex::<_>::new(42);
228
    ///
229
    /// let maybe_guard = lock.try_lock();
230
    /// assert!(maybe_guard.is_some());
231
    ///
232
    /// // `maybe_guard` is still held, so the second call fails
233
    /// let maybe_guard2 = lock.try_lock();
234
    /// assert!(maybe_guard2.is_none());
235
    /// ```
236
    #[inline(always)]
237
0
    pub fn try_lock(&self) -> Option<SpinMutexGuard<T>> {
238
        // The reason for using a strong compare_exchange is explained here:
239
        // https://github.com/Amanieu/parking_lot/pull/207#issuecomment-575869107
240
0
        if self
241
0
            .lock
242
0
            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
243
0
            .is_ok()
244
        {
245
0
            Some(SpinMutexGuard {
246
0
                lock: &self.lock,
247
0
                data: unsafe { &mut *self.data.get() },
248
0
            })
249
        } else {
250
0
            None
251
        }
252
0
    }
253
254
    /// Returns a mutable reference to the underlying data.
255
    ///
256
    /// Since this call borrows the [`SpinMutex`] mutably, and a mutable reference is guaranteed to be exclusive in
257
    /// Rust, no actual locking needs to take place -- the mutable borrow statically guarantees no locks exist. As
258
    /// such, this is a 'zero-cost' operation.
259
    ///
260
    /// # Example
261
    ///
262
    /// ```
263
    /// let mut lock = spin::mutex::SpinMutex::<_>::new(0);
264
    /// *lock.get_mut() = 10;
265
    /// assert_eq!(*lock.lock(), 10);
266
    /// ```
267
    #[inline(always)]
268
0
    pub fn get_mut(&mut self) -> &mut T {
269
        // We know statically that there are no other references to `self`, so
270
        // there's no need to lock the inner mutex.
271
0
        unsafe { &mut *self.data.get() }
272
0
    }
273
}
274
275
impl<T: ?Sized + fmt::Debug, R> fmt::Debug for SpinMutex<T, R> {
276
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277
0
        match self.try_lock() {
278
0
            Some(guard) => write!(f, "Mutex {{ data: ")
279
0
                .and_then(|()| (&*guard).fmt(f))
280
0
                .and_then(|()| write!(f, "}}")),
281
0
            None => write!(f, "Mutex {{ <locked> }}"),
282
        }
283
0
    }
284
}
285
286
impl<T: ?Sized + Default, R> Default for SpinMutex<T, R> {
287
0
    fn default() -> Self {
288
0
        Self::new(Default::default())
289
0
    }
290
}
291
292
impl<T, R> From<T> for SpinMutex<T, R> {
293
0
    fn from(data: T) -> Self {
294
0
        Self::new(data)
295
0
    }
296
}
297
298
impl<'a, T: ?Sized> SpinMutexGuard<'a, T> {
299
    /// Leak the lock guard, yielding a mutable reference to the underlying data.
300
    ///
301
    /// Note that this function will permanently lock the original [`SpinMutex`].
302
    ///
303
    /// ```
304
    /// let mylock = spin::mutex::SpinMutex::<_>::new(0);
305
    ///
306
    /// let data: &mut i32 = spin::mutex::SpinMutexGuard::leak(mylock.lock());
307
    ///
308
    /// *data = 1;
309
    /// assert_eq!(*data, 1);
310
    /// ```
311
    #[inline(always)]
312
0
    pub fn leak(this: Self) -> &'a mut T {
313
        // Use ManuallyDrop to avoid stacked-borrow invalidation
314
0
        let mut this = ManuallyDrop::new(this);
315
        // We know statically that only we are referencing data
316
0
        unsafe { &mut *this.data }
317
0
    }
318
}
319
320
impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for SpinMutexGuard<'a, T> {
321
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322
0
        fmt::Debug::fmt(&**self, f)
323
0
    }
324
}
325
326
impl<'a, T: ?Sized + fmt::Display> fmt::Display for SpinMutexGuard<'a, T> {
327
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328
0
        fmt::Display::fmt(&**self, f)
329
0
    }
330
}
331
332
impl<'a, T: ?Sized> Deref for SpinMutexGuard<'a, T> {
333
    type Target = T;
334
0
    fn deref(&self) -> &T {
335
        // We know statically that only we are referencing data
336
0
        unsafe { &*self.data }
337
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>> as core::ops::deref::Deref>::deref
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<_> as core::ops::deref::Deref>::deref
338
}
339
340
impl<'a, T: ?Sized> DerefMut for SpinMutexGuard<'a, T> {
341
0
    fn deref_mut(&mut self) -> &mut T {
342
        // We know statically that only we are referencing data
343
0
        unsafe { &mut *self.data }
344
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<dyn spdmlib::common::SpdmTransportEncap + core::marker::Sync + core::marker::Send> as core::ops::deref::DerefMut>::deref_mut
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>> as core::ops::deref::DerefMut>::deref_mut
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<_> as core::ops::deref::DerefMut>::deref_mut
345
}
346
347
impl<'a, T: ?Sized> Drop for SpinMutexGuard<'a, T> {
348
    /// The dropping of the MutexGuard will release the lock it was created from.
349
0
    fn drop(&mut self) {
350
0
        self.lock.store(false, Ordering::Release);
351
0
    }
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<dyn spdmlib::common::SpdmDeviceIo + core::marker::Sync + core::marker::Send> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<alloc::collections::vec_deque::VecDeque<u8>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<spdmlib::responder::context::ResponderContext> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<&mut [u8]> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<dyn spdmlib::common::SpdmTransportEncap + core::marker::Sync + core::marker::Send> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<alloc::collections::btree::map::BTreeMap<usize, alloc::boxed::Box<ring::digest::Context>>> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<_> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <spin::mutex::spin::SpinMutexGuard<fuzzlib::fake_device_io::FakeSpdmDeviceIoReceve> as core::ops::drop::Drop>::drop
352
}
353
354
#[cfg(feature = "lock_api")]
355
unsafe impl<R: RelaxStrategy> lock_api_crate::RawMutex for SpinMutex<(), R> {
356
    type GuardMarker = lock_api_crate::GuardSend;
357
358
    const INIT: Self = Self::new(());
359
360
0
    fn lock(&self) {
361
        // Prevent guard destructor running
362
0
        core::mem::forget(Self::lock(self));
363
0
    }
364
365
0
    fn try_lock(&self) -> bool {
366
        // Prevent guard destructor running
367
0
        Self::try_lock(self).map(core::mem::forget).is_some()
368
0
    }
369
370
0
    unsafe fn unlock(&self) {
371
0
        self.force_unlock();
372
0
    }
373
374
0
    fn is_locked(&self) -> bool {
375
0
        Self::is_locked(self)
376
0
    }
377
}
378
379
#[cfg(test)]
380
mod tests {
381
    use std::prelude::v1::*;
382
383
    use std::sync::atomic::{AtomicUsize, Ordering};
384
    use std::sync::mpsc::channel;
385
    use std::sync::Arc;
386
    use std::thread;
387
388
    type SpinMutex<T> = super::SpinMutex<T>;
389
390
    #[derive(Eq, PartialEq, Debug)]
391
    struct NonCopy(i32);
392
393
    #[test]
394
    fn smoke() {
395
        let m = SpinMutex::<_>::new(());
396
        drop(m.lock());
397
        drop(m.lock());
398
    }
399
400
    #[test]
401
    fn lots_and_lots() {
402
        static M: SpinMutex<()> = SpinMutex::<_>::new(());
403
        static mut CNT: u32 = 0;
404
        const J: u32 = 1000;
405
        const K: u32 = 3;
406
407
        fn inc() {
408
            for _ in 0..J {
409
                unsafe {
410
                    let _g = M.lock();
411
                    CNT += 1;
412
                }
413
            }
414
        }
415
416
        let (tx, rx) = channel();
417
        let mut ts = Vec::new();
418
        for _ in 0..K {
419
            let tx2 = tx.clone();
420
            ts.push(thread::spawn(move || {
421
                inc();
422
                tx2.send(()).unwrap();
423
            }));
424
            let tx2 = tx.clone();
425
            ts.push(thread::spawn(move || {
426
                inc();
427
                tx2.send(()).unwrap();
428
            }));
429
        }
430
431
        drop(tx);
432
        for _ in 0..2 * K {
433
            rx.recv().unwrap();
434
        }
435
        assert_eq!(unsafe { CNT }, J * K * 2);
436
437
        for t in ts {
438
            t.join().unwrap();
439
        }
440
    }
441
442
    #[test]
443
    fn try_lock() {
444
        let mutex = SpinMutex::<_>::new(42);
445
446
        // First lock succeeds
447
        let a = mutex.try_lock();
448
        assert_eq!(a.as_ref().map(|r| **r), Some(42));
449
450
        // Additional lock fails
451
        let b = mutex.try_lock();
452
        assert!(b.is_none());
453
454
        // After dropping lock, it succeeds again
455
        ::core::mem::drop(a);
456
        let c = mutex.try_lock();
457
        assert_eq!(c.as_ref().map(|r| **r), Some(42));
458
    }
459
460
    #[test]
461
    fn test_into_inner() {
462
        let m = SpinMutex::<_>::new(NonCopy(10));
463
        assert_eq!(m.into_inner(), NonCopy(10));
464
    }
465
466
    #[test]
467
    fn test_into_inner_drop() {
468
        struct Foo(Arc<AtomicUsize>);
469
        impl Drop for Foo {
470
            fn drop(&mut self) {
471
                self.0.fetch_add(1, Ordering::SeqCst);
472
            }
473
        }
474
        let num_drops = Arc::new(AtomicUsize::new(0));
475
        let m = SpinMutex::<_>::new(Foo(num_drops.clone()));
476
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
477
        {
478
            let _inner = m.into_inner();
479
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
480
        }
481
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
482
    }
483
484
    #[test]
485
    fn test_mutex_arc_nested() {
486
        // Tests nested mutexes and access
487
        // to underlying data.
488
        let arc = Arc::new(SpinMutex::<_>::new(1));
489
        let arc2 = Arc::new(SpinMutex::<_>::new(arc));
490
        let (tx, rx) = channel();
491
        let t = thread::spawn(move || {
492
            let lock = arc2.lock();
493
            let lock2 = lock.lock();
494
            assert_eq!(*lock2, 1);
495
            tx.send(()).unwrap();
496
        });
497
        rx.recv().unwrap();
498
        t.join().unwrap();
499
    }
500
501
    #[test]
502
    fn test_mutex_arc_access_in_unwind() {
503
        let arc = Arc::new(SpinMutex::<_>::new(1));
504
        let arc2 = arc.clone();
505
        let _ = thread::spawn(move || -> () {
506
            struct Unwinder {
507
                i: Arc<SpinMutex<i32>>,
508
            }
509
            impl Drop for Unwinder {
510
                fn drop(&mut self) {
511
                    *self.i.lock() += 1;
512
                }
513
            }
514
            let _u = Unwinder { i: arc2 };
515
            panic!();
516
        })
517
        .join();
518
        let lock = arc.lock();
519
        assert_eq!(*lock, 2);
520
    }
521
522
    #[test]
523
    fn test_mutex_unsized() {
524
        let mutex: &SpinMutex<[i32]> = &SpinMutex::<_>::new([1, 2, 3]);
525
        {
526
            let b = &mut *mutex.lock();
527
            b[0] = 4;
528
            b[2] = 5;
529
        }
530
        let comp: &[i32] = &[4, 2, 5];
531
        assert_eq!(&*mutex.lock(), comp);
532
    }
533
534
    #[test]
535
    fn test_mutex_force_lock() {
536
        let lock = SpinMutex::<_>::new(());
537
        ::std::mem::forget(lock.lock());
538
        unsafe {
539
            lock.force_unlock();
540
        }
541
        assert!(lock.try_lock().is_some());
542
    }
543
}