summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-core/src/spin/mutex.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-core/src/spin/mutex.rs')
-rw-r--r--vendor/tracing-core/src/spin/mutex.rs118
1 files changed, 118 insertions, 0 deletions
diff --git a/vendor/tracing-core/src/spin/mutex.rs b/vendor/tracing-core/src/spin/mutex.rs
new file mode 100644
index 000000000..c261a6191
--- /dev/null
+++ b/vendor/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);
+ }
+}