• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)]
new(data: T) -> Self110     pub const fn new(data: T) -> Self {
111         SpinMutex {
112             lock: AtomicBool::new(false),
113             data: UnsafeCell::new(data),
114             phantom: PhantomData,
115         }
116     }
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)]
into_inner(self) -> T127     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         let SpinMutex { data, .. } = self;
131         data.into_inner()
132     }
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)]
as_mut_ptr(&self) -> *mut T156     pub fn as_mut_ptr(&self) -> *mut T {
157         self.data.get()
158     }
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)]
lock(&self) -> SpinMutexGuard<T>177     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         while self
181             .lock
182             .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
183             .is_err()
184         {
185             // Wait until the lock looks unlocked before retrying
186             while self.is_locked() {
187                 R::relax();
188             }
189         }
190 
191         SpinMutexGuard {
192             lock: &self.lock,
193             data: unsafe { &mut *self.data.get() },
194         }
195     }
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)]
is_locked(&self) -> bool206     pub fn is_locked(&self) -> bool {
207         self.lock.load(Ordering::Relaxed)
208     }
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)]
force_unlock(&self)218     pub unsafe fn force_unlock(&self) {
219         self.lock.store(false, Ordering::Release);
220     }
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)]
try_lock(&self) -> Option<SpinMutexGuard<T>>237     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         if self
241             .lock
242             .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
243             .is_ok()
244         {
245             Some(SpinMutexGuard {
246                 lock: &self.lock,
247                 data: unsafe { &mut *self.data.get() },
248             })
249         } else {
250             None
251         }
252     }
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)]
get_mut(&mut self) -> &mut T268     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         unsafe { &mut *self.data.get() }
272     }
273 }
274 
275 impl<T: ?Sized + fmt::Debug, R> fmt::Debug for SpinMutex<T, R> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result276     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277         match self.try_lock() {
278             Some(guard) => write!(f, "Mutex {{ data: ")
279                 .and_then(|()| (&*guard).fmt(f))
280                 .and_then(|()| write!(f, "}}")),
281             None => write!(f, "Mutex {{ <locked> }}"),
282         }
283     }
284 }
285 
286 impl<T: ?Sized + Default, R> Default for SpinMutex<T, R> {
default() -> Self287     fn default() -> Self {
288         Self::new(Default::default())
289     }
290 }
291 
292 impl<T, R> From<T> for SpinMutex<T, R> {
from(data: T) -> Self293     fn from(data: T) -> Self {
294         Self::new(data)
295     }
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)]
leak(this: Self) -> &'a mut T312     pub fn leak(this: Self) -> &'a mut T {
313         // Use ManuallyDrop to avoid stacked-borrow invalidation
314         let mut this = ManuallyDrop::new(this);
315         // We know statically that only we are referencing data
316         unsafe { &mut *this.data }
317     }
318 }
319 
320 impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for SpinMutexGuard<'a, T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result321     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322         fmt::Debug::fmt(&**self, f)
323     }
324 }
325 
326 impl<'a, T: ?Sized + fmt::Display> fmt::Display for SpinMutexGuard<'a, T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result327     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328         fmt::Display::fmt(&**self, f)
329     }
330 }
331 
332 impl<'a, T: ?Sized> Deref for SpinMutexGuard<'a, T> {
333     type Target = T;
deref(&self) -> &T334     fn deref(&self) -> &T {
335         // We know statically that only we are referencing data
336         unsafe { &*self.data }
337     }
338 }
339 
340 impl<'a, T: ?Sized> DerefMut for SpinMutexGuard<'a, T> {
deref_mut(&mut self) -> &mut T341     fn deref_mut(&mut self) -> &mut T {
342         // We know statically that only we are referencing data
343         unsafe { &mut *self.data }
344     }
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.
drop(&mut self)349     fn drop(&mut self) {
350         self.lock.store(false, Ordering::Release);
351     }
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 
lock(&self)360     fn lock(&self) {
361         // Prevent guard destructor running
362         core::mem::forget(Self::lock(self));
363     }
364 
try_lock(&self) -> bool365     fn try_lock(&self) -> bool {
366         // Prevent guard destructor running
367         Self::try_lock(self).map(core::mem::forget).is_some()
368     }
369 
unlock(&self)370     unsafe fn unlock(&self) {
371         self.force_unlock();
372     }
373 
is_locked(&self) -> bool374     fn is_locked(&self) -> bool {
375         Self::is_locked(self)
376     }
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]
smoke()394     fn smoke() {
395         let m = SpinMutex::<_>::new(());
396         drop(m.lock());
397         drop(m.lock());
398     }
399 
400     #[test]
lots_and_lots()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]
try_lock()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]
test_into_inner()461     fn test_into_inner() {
462         let m = SpinMutex::<_>::new(NonCopy(10));
463         assert_eq!(m.into_inner(), NonCopy(10));
464     }
465 
466     #[test]
test_into_inner_drop()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]
test_mutex_arc_nested()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     #[ignore = "Android uses panic_abort"]
test_mutex_arc_access_in_unwind()503     fn test_mutex_arc_access_in_unwind() {
504         let arc = Arc::new(SpinMutex::<_>::new(1));
505         let arc2 = arc.clone();
506         let _ = thread::spawn(move || -> () {
507             struct Unwinder {
508                 i: Arc<SpinMutex<i32>>,
509             }
510             impl Drop for Unwinder {
511                 fn drop(&mut self) {
512                     *self.i.lock() += 1;
513                 }
514             }
515             let _u = Unwinder { i: arc2 };
516             panic!();
517         })
518         .join();
519         let lock = arc.lock();
520         assert_eq!(*lock, 2);
521     }
522 
523     #[test]
test_mutex_unsized()524     fn test_mutex_unsized() {
525         let mutex: &SpinMutex<[i32]> = &SpinMutex::<_>::new([1, 2, 3]);
526         {
527             let b = &mut *mutex.lock();
528             b[0] = 4;
529             b[2] = 5;
530         }
531         let comp: &[i32] = &[4, 2, 5];
532         assert_eq!(&*mutex.lock(), comp);
533     }
534 
535     #[test]
test_mutex_force_lock()536     fn test_mutex_force_lock() {
537         let lock = SpinMutex::<_>::new(());
538         ::std::mem::forget(lock.lock());
539         unsafe {
540             lock.force_unlock();
541         }
542         assert!(lock.try_lock().is_some());
543     }
544 }
545