1 //! Trivial spinlock-based implementation of `sync::Mutex`. 2 // FIXME: Perhaps use Intel TSX to avoid locking? 3 4 #[cfg(test)] 5 mod tests; 6 7 use crate::std::cell::UnsafeCell; 8 use crate::std::hint; 9 use crate::std::ops::{Deref, DerefMut}; 10 use crate::std::sync::atomic::{AtomicBool, Ordering}; 11 12 #[derive(Default)] 13 pub struct SpinMutex<T> { 14 value: UnsafeCell<T>, 15 lock: AtomicBool, 16 } 17 18 unsafe impl<T: Send> Send for SpinMutex<T> {} 19 unsafe impl<T: Send> Sync for SpinMutex<T> {} 20 21 pub struct SpinMutexGuard<'a, T: 'a> { 22 mutex: &'a SpinMutex<T>, 23 } 24 25 impl<'a, T> !Send for SpinMutexGuard<'a, T> {} 26 unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} 27 28 impl<T> SpinMutex<T> { 29 pub const fn new(value: T) -> Self { 30 SpinMutex { 31 value: UnsafeCell::new(value), 32 lock: AtomicBool::new(false), 33 } 34 } 35 36 #[inline(always)] 37 pub fn lock(&self) -> SpinMutexGuard<'_, T> { 38 loop { 39 match self.try_lock() { 40 None => { 41 while self.lock.load(Ordering::Relaxed) { 42 hint::spin_loop() 43 } 44 } 45 Some(guard) => return guard, 46 } 47 } 48 } 49 50 #[inline(always)] 51 pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> { 52 if self 53 .lock 54 .compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) 55 .is_ok() 56 { 57 Some(SpinMutexGuard { mutex: self }) 58 } else { 59 None 60 } 61 } 62 } 63 64 /// Lock the Mutex or return false. 65 pub macro try_lock_or_false($e:expr) { 66 if let Some(v) = $e.try_lock() { 67 v 68 } else { 69 return false; 70 } 71 } 72 73 impl<'a, T> Deref for SpinMutexGuard<'a, T> { 74 type Target = T; 75 76 fn deref(&self) -> &T { 77 unsafe { &*self.mutex.value.get() } 78 } 79 } 80 81 impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { 82 fn deref_mut(&mut self) -> &mut T { 83 unsafe { &mut *self.mutex.value.get() } 84 } 85 } 86 87 impl<'a, T> Drop for SpinMutexGuard<'a, T> { 88 fn drop(&mut self) { 89 self.mutex.lock.store(false, Ordering::Release) 90 } 91 } 92