diff options
Diffstat (limited to 'third_party/rust/tracing-core/src/spin/mutex.rs')
-rw-r--r-- | third_party/rust/tracing-core/src/spin/mutex.rs | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/third_party/rust/tracing-core/src/spin/mutex.rs b/third_party/rust/tracing-core/src/spin/mutex.rs new file mode 100644 index 0000000000..c261a61910 --- /dev/null +++ b/third_party/rust/tracing-core/src/spin/mutex.rs @@ -0,0 +1,118 @@ +use core::cell::UnsafeCell; +use core::default::Default; +use core::fmt; +use core::hint; +use core::marker::Sync; +use core::ops::{Deref, DerefMut, Drop}; +use core::option::Option::{self, None, Some}; +use core::sync::atomic::{AtomicBool, Ordering}; + +/// This type provides MUTual EXclusion based on spinning. +pub(crate) 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(crate) struct MutexGuard<'a, T: ?Sized> { + 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. + pub(crate) const fn new(user_data: T) -> Mutex<T> { + Mutex { + lock: AtomicBool::new(false), + data: UnsafeCell::new(user_data), + } + } +} + +impl<T: ?Sized> Mutex<T> { + fn obtain_lock(&self) { + while self + .lock + .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_err() + { + // Wait until the lock looks unlocked before retrying + while self.lock.load(Ordering::Relaxed) { + hint::spin_loop(); + } + } + } + + /// 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. + pub(crate) fn lock(&self) -> MutexGuard<'_, T> { + self.obtain_lock(); + MutexGuard { + lock: &self.lock, + data: unsafe { &mut *self.data.get() }, + } + } + + /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns + /// a guard within Some. + pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> { + if self + .lock + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + { + 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); + } +} |