|  | use core::sync::atomic::{AtomicBool, Ordering, spin_loop_hint as cpu_relax}; | 
|  | use core::cell::UnsafeCell; | 
|  | use core::marker::Sync; | 
|  | use core::ops::{Drop, Deref, DerefMut}; | 
|  | use core::fmt; | 
|  | use core::option::Option::{self, None, Some}; | 
|  | use core::default::Default; | 
|  |  | 
|  | /// This type provides MUTual EXclusion based on spinning. | 
|  | /// | 
|  | /// # Description | 
|  | /// | 
|  | /// The behaviour of these lock is similar to their namesakes in `std::sync`. they | 
|  | /// differ on the following: | 
|  | /// | 
|  | /// - The lock will not be poisoned in case of failure; | 
|  | /// | 
|  | /// # Simple examples | 
|  | /// | 
|  | /// ``` | 
|  | /// use spin; | 
|  | /// let spin_mutex = spin::Mutex::new(0); | 
|  | /// | 
|  | /// // Modify the data | 
|  | /// { | 
|  | ///     let mut data = spin_mutex.lock(); | 
|  | ///     *data = 2; | 
|  | /// } | 
|  | /// | 
|  | /// // Read the data | 
|  | /// let answer = | 
|  | /// { | 
|  | ///     let data = spin_mutex.lock(); | 
|  | ///     *data | 
|  | /// }; | 
|  | /// | 
|  | /// assert_eq!(answer, 2); | 
|  | /// ``` | 
|  | /// | 
|  | /// # Thread-safety example | 
|  | /// | 
|  | /// ``` | 
|  | /// use spin; | 
|  | /// use std::sync::{Arc, Barrier}; | 
|  | /// | 
|  | /// let numthreads = 1000; | 
|  | /// let spin_mutex = Arc::new(spin::Mutex::new(0)); | 
|  | /// | 
|  | /// // We use a barrier to ensure the readout happens after all writing | 
|  | /// let barrier = Arc::new(Barrier::new(numthreads + 1)); | 
|  | /// | 
|  | /// for _ in (0..numthreads) | 
|  | /// { | 
|  | ///     let my_barrier = barrier.clone(); | 
|  | ///     let my_lock = spin_mutex.clone(); | 
|  | ///     std::thread::spawn(move|| | 
|  | ///     { | 
|  | ///         let mut guard = my_lock.lock(); | 
|  | ///         *guard += 1; | 
|  | /// | 
|  | ///         // Release the lock to prevent a deadlock | 
|  | ///         drop(guard); | 
|  | ///         my_barrier.wait(); | 
|  | ///     }); | 
|  | /// } | 
|  | /// | 
|  | /// barrier.wait(); | 
|  | /// | 
|  | /// let answer = { *spin_mutex.lock() }; | 
|  | /// assert_eq!(answer, numthreads); | 
|  | /// ``` | 
|  | pub struct Mutex<T: ?Sized> | 
|  | { | 
|  | lock: AtomicBool, | 
|  | data: UnsafeCell<T>, | 
|  | } | 
|  |  | 
|  | /// A guard to which the protected data can be accessed | 
|  | /// | 
|  | /// When the guard falls out of scope it will release the lock. | 
|  | #[derive(Debug)] | 
|  | pub struct MutexGuard<'a, T: ?Sized + 'a> | 
|  | { | 
|  | lock: &'a AtomicBool, | 
|  | data: &'a mut T, | 
|  | } | 
|  |  | 
|  | // Same unsafe impls as `std::sync::Mutex` | 
|  | unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} | 
|  | unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} | 
|  |  | 
|  | impl<T> Mutex<T> | 
|  | { | 
|  | /// Creates a new spinlock wrapping the supplied data. | 
|  | /// | 
|  | /// May be used statically: | 
|  | /// | 
|  | /// ``` | 
|  | /// use spin; | 
|  | /// | 
|  | /// static MUTEX: spin::Mutex<()> = spin::Mutex::new(()); | 
|  | /// | 
|  | /// fn demo() { | 
|  | ///     let lock = MUTEX.lock(); | 
|  | ///     // do something with lock | 
|  | ///     drop(lock); | 
|  | /// } | 
|  | /// ``` | 
|  | pub const fn new(user_data: T) -> Mutex<T> | 
|  | { | 
|  | Mutex | 
|  | { | 
|  | lock: AtomicBool::new(false), | 
|  | data: UnsafeCell::new(user_data), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Consumes this mutex, returning the underlying data. | 
|  | pub fn into_inner(self) -> T { | 
|  | // We know statically that there are no outstanding references to | 
|  | // `self` so there's no need to lock. | 
|  | let Mutex { data, .. } = self; | 
|  | data.into_inner() | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T: ?Sized> Mutex<T> | 
|  | { | 
|  | fn obtain_lock(&self) | 
|  | { | 
|  | while self.lock.compare_and_swap(false, true, Ordering::Acquire) != false | 
|  | { | 
|  | // Wait until the lock looks unlocked before retrying | 
|  | while self.lock.load(Ordering::Relaxed) | 
|  | { | 
|  | cpu_relax(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Locks the spinlock and returns a guard. | 
|  | /// | 
|  | /// The returned value may be dereferenced for data access | 
|  | /// and the lock will be dropped when the guard falls out of scope. | 
|  | /// | 
|  | /// ``` | 
|  | /// let mylock = spin::Mutex::new(0); | 
|  | /// { | 
|  | ///     let mut data = mylock.lock(); | 
|  | ///     // The lock is now locked and the data can be accessed | 
|  | ///     *data += 1; | 
|  | ///     // The lock is implicitly dropped | 
|  | /// } | 
|  | /// | 
|  | /// ``` | 
|  | pub fn lock(&self) -> MutexGuard<T> | 
|  | { | 
|  | self.obtain_lock(); | 
|  | MutexGuard | 
|  | { | 
|  | lock: &self.lock, | 
|  | data: unsafe { &mut *self.data.get() }, | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Force unlock the spinlock. | 
|  | /// | 
|  | /// This is *extremely* unsafe if the lock is not held by the current | 
|  | /// thread. However, this can be useful in some instances for exposing the | 
|  | /// lock to FFI that doesn't know how to deal with RAII. | 
|  | /// | 
|  | /// If the lock isn't held, this is a no-op. | 
|  | pub unsafe fn force_unlock(&self) { | 
|  | self.lock.store(false, Ordering::Release); | 
|  | } | 
|  |  | 
|  | /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns | 
|  | /// a guard within Some. | 
|  | pub fn try_lock(&self) -> Option<MutexGuard<T>> | 
|  | { | 
|  | if self.lock.compare_and_swap(false, true, Ordering::Acquire) == false | 
|  | { | 
|  | Some( | 
|  | MutexGuard { | 
|  | lock: &self.lock, | 
|  | data: unsafe { &mut *self.data.get() }, | 
|  | } | 
|  | ) | 
|  | } | 
|  | else | 
|  | { | 
|  | None | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> | 
|  | { | 
|  | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result | 
|  | { | 
|  | match self.try_lock() | 
|  | { | 
|  | Some(guard) => write!(f, "Mutex {{ data: ") | 
|  | .and_then(|()| (&*guard).fmt(f)) | 
|  | .and_then(|()| write!(f, "}}")), | 
|  | None => write!(f, "Mutex {{ <locked> }}"), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<T: ?Sized + Default> Default for Mutex<T> { | 
|  | fn default() -> Mutex<T> { | 
|  | Mutex::new(Default::default()) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> | 
|  | { | 
|  | type Target = T; | 
|  | fn deref<'b>(&'b self) -> &'b T { &*self.data } | 
|  | } | 
|  |  | 
|  | impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> | 
|  | { | 
|  | fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data } | 
|  | } | 
|  |  | 
|  | impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> | 
|  | { | 
|  | /// The dropping of the MutexGuard will release the lock it was created from. | 
|  | fn drop(&mut self) | 
|  | { | 
|  | self.lock.store(false, Ordering::Release); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[cfg(test)] | 
|  | mod tests { | 
|  | use std::prelude::v1::*; | 
|  |  | 
|  | use std::sync::mpsc::channel; | 
|  | use std::sync::Arc; | 
|  | use std::sync::atomic::{AtomicUsize, Ordering}; | 
|  | use std::thread; | 
|  |  | 
|  | use super::*; | 
|  |  | 
|  | #[derive(Eq, PartialEq, Debug)] | 
|  | struct NonCopy(i32); | 
|  |  | 
|  | #[test] | 
|  | fn smoke() { | 
|  | let m = Mutex::new(()); | 
|  | drop(m.lock()); | 
|  | drop(m.lock()); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn lots_and_lots() { | 
|  | static M: Mutex<()>  = Mutex::new(()); | 
|  | static mut CNT: u32 = 0; | 
|  | const J: u32 = 1000; | 
|  | const K: u32 = 3; | 
|  |  | 
|  | fn inc() { | 
|  | for _ in 0..J { | 
|  | unsafe { | 
|  | let _g = M.lock(); | 
|  | CNT += 1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | let (tx, rx) = channel(); | 
|  | for _ in 0..K { | 
|  | let tx2 = tx.clone(); | 
|  | thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); | 
|  | let tx2 = tx.clone(); | 
|  | thread::spawn(move|| { inc(); tx2.send(()).unwrap(); }); | 
|  | } | 
|  |  | 
|  | drop(tx); | 
|  | for _ in 0..2 * K { | 
|  | rx.recv().unwrap(); | 
|  | } | 
|  | assert_eq!(unsafe {CNT}, J * K * 2); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn try_lock() { | 
|  | let mutex = Mutex::new(42); | 
|  |  | 
|  | // First lock succeeds | 
|  | let a = mutex.try_lock(); | 
|  | assert_eq!(a.as_ref().map(|r| **r), Some(42)); | 
|  |  | 
|  | // Additional lock failes | 
|  | let b = mutex.try_lock(); | 
|  | assert!(b.is_none()); | 
|  |  | 
|  | // After dropping lock, it succeeds again | 
|  | ::core::mem::drop(a); | 
|  | let c = mutex.try_lock(); | 
|  | assert_eq!(c.as_ref().map(|r| **r), Some(42)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_into_inner() { | 
|  | let m = Mutex::new(NonCopy(10)); | 
|  | assert_eq!(m.into_inner(), NonCopy(10)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_into_inner_drop() { | 
|  | struct Foo(Arc<AtomicUsize>); | 
|  | impl Drop for Foo { | 
|  | fn drop(&mut self) { | 
|  | self.0.fetch_add(1, Ordering::SeqCst); | 
|  | } | 
|  | } | 
|  | let num_drops = Arc::new(AtomicUsize::new(0)); | 
|  | let m = Mutex::new(Foo(num_drops.clone())); | 
|  | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | 
|  | { | 
|  | let _inner = m.into_inner(); | 
|  | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | 
|  | } | 
|  | assert_eq!(num_drops.load(Ordering::SeqCst), 1); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_mutex_arc_nested() { | 
|  | // Tests nested mutexes and access | 
|  | // to underlying data. | 
|  | let arc = Arc::new(Mutex::new(1)); | 
|  | let arc2 = Arc::new(Mutex::new(arc)); | 
|  | let (tx, rx) = channel(); | 
|  | let _t = thread::spawn(move|| { | 
|  | let lock = arc2.lock(); | 
|  | let lock2 = lock.lock(); | 
|  | assert_eq!(*lock2, 1); | 
|  | tx.send(()).unwrap(); | 
|  | }); | 
|  | rx.recv().unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_mutex_arc_access_in_unwind() { | 
|  | let arc = Arc::new(Mutex::new(1)); | 
|  | let arc2 = arc.clone(); | 
|  | let _ = thread::spawn(move|| -> () { | 
|  | struct Unwinder { | 
|  | i: Arc<Mutex<i32>>, | 
|  | } | 
|  | impl Drop for Unwinder { | 
|  | fn drop(&mut self) { | 
|  | *self.i.lock() += 1; | 
|  | } | 
|  | } | 
|  | let _u = Unwinder { i: arc2 }; | 
|  | panic!(); | 
|  | }).join(); | 
|  | let lock = arc.lock(); | 
|  | assert_eq!(*lock, 2); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_mutex_unsized() { | 
|  | let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); | 
|  | { | 
|  | let b = &mut *mutex.lock(); | 
|  | b[0] = 4; | 
|  | b[2] = 5; | 
|  | } | 
|  | let comp: &[i32] = &[4, 2, 5]; | 
|  | assert_eq!(&*mutex.lock(), comp); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_mutex_force_lock() { | 
|  | let lock = Mutex::new(()); | 
|  | ::std::mem::forget(lock.lock()); | 
|  | unsafe { | 
|  | lock.force_unlock(); | 
|  | } | 
|  | assert!(lock.try_lock().is_some()); | 
|  | } | 
|  | } |