| //! Trivial spinlock-based implementation of `sync::Mutex`. | |
| // FIXME: Perhaps use Intel TSX to avoid locking? | |
| #[cfg(test)] | |
| mod tests; | |
| use crate::cell::UnsafeCell; | |
| use crate::hint; | |
| use crate::ops::{Deref, DerefMut}; | |
| use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; | |
| #[derive(Default)] | |
| pub struct SpinMutex<T> { | |
| value: UnsafeCell<T>, | |
| lock: Atomic<bool>, | |
| } | |
| unsafe impl<T: Send> Send for SpinMutex<T> {} | |
| unsafe impl<T: Send> Sync for SpinMutex<T> {} | |
| pub struct SpinMutexGuard<'a, T: 'a> { | |
| mutex: &'a SpinMutex<T>, | |
| } | |
| impl<'a, T> !Send for SpinMutexGuard<'a, T> {} | |
| unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} | |
| impl<T> SpinMutex<T> { | |
| pub const fn new(value: T) -> Self { | |
| SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) } | |
| } | |
| #[inline(always)] | |
| pub fn lock(&self) -> SpinMutexGuard<'_, T> { | |
| loop { | |
| match self.try_lock() { | |
| None => { | |
| while self.lock.load(Ordering::Relaxed) { | |
| hint::spin_loop() | |
| } | |
| } | |
| Some(guard) => return guard, | |
| } | |
| } | |
| } | |
| #[inline(always)] | |
| pub fn try_lock(&self) -> Option<SpinMutexGuard<'_, T>> { | |
| if self.lock.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire).is_ok() { | |
| Some(SpinMutexGuard { mutex: self }) | |
| } else { | |
| None | |
| } | |
| } | |
| } | |
| /// Lock the Mutex or return false. | |
| pub macro try_lock_or_false($e:expr) { | |
| if let Some(v) = $e.try_lock() { v } else { return false } | |
| } | |
| impl<'a, T> Deref for SpinMutexGuard<'a, T> { | |
| type Target = T; | |
| fn deref(&self) -> &T { | |
| unsafe { &*self.mutex.value.get() } | |
| } | |
| } | |
| impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { | |
| fn deref_mut(&mut self) -> &mut T { | |
| unsafe { &mut *self.mutex.value.get() } | |
| } | |
| } | |
| impl<'a, T> Drop for SpinMutexGuard<'a, T> { | |
| fn drop(&mut self) { | |
| self.mutex.lock.store(false, Ordering::Release) | |
| } | |
| } |