• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use core::cell::UnsafeCell;
2 use core::default::Default;
3 use core::fmt;
4 use core::hint;
5 use core::marker::Sync;
6 use core::ops::{Deref, DerefMut, Drop};
7 use core::option::Option::{self, None, Some};
8 use core::sync::atomic::{AtomicBool, Ordering};
9 
10 /// This type provides MUTual EXclusion based on spinning.
11 pub(crate) struct Mutex<T: ?Sized> {
12     lock: AtomicBool,
13     data: UnsafeCell<T>,
14 }
15 
16 /// A guard to which the protected data can be accessed
17 ///
18 /// When the guard falls out of scope it will release the lock.
19 #[derive(Debug)]
20 pub(crate) struct MutexGuard<'a, T: ?Sized> {
21     lock: &'a AtomicBool,
22     data: &'a mut T,
23 }
24 
25 // Same unsafe impls as `std::sync::Mutex`
26 unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
27 unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
28 
29 impl<T> Mutex<T> {
30     /// Creates a new spinlock wrapping the supplied data.
new(user_data: T) -> Mutex<T>31     pub(crate) const fn new(user_data: T) -> Mutex<T> {
32         Mutex {
33             lock: AtomicBool::new(false),
34             data: UnsafeCell::new(user_data),
35         }
36     }
37 }
38 
39 impl<T: ?Sized> Mutex<T> {
obtain_lock(&self)40     fn obtain_lock(&self) {
41         while self
42             .lock
43             .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
44             .is_err()
45         {
46             // Wait until the lock looks unlocked before retrying
47             while self.lock.load(Ordering::Relaxed) {
48                 hint::spin_loop();
49             }
50         }
51     }
52 
53     /// Locks the spinlock and returns a guard.
54     ///
55     /// The returned value may be dereferenced for data access
56     /// and the lock will be dropped when the guard falls out of scope.
lock(&self) -> MutexGuard<'_, T>57     pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
58         self.obtain_lock();
59         MutexGuard {
60             lock: &self.lock,
61             data: unsafe { &mut *self.data.get() },
62         }
63     }
64 
65     /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
66     /// a guard within Some.
try_lock(&self) -> Option<MutexGuard<'_, T>>67     pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
68         if self
69             .lock
70             .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
71             .is_ok()
72         {
73             Some(MutexGuard {
74                 lock: &self.lock,
75                 data: unsafe { &mut *self.data.get() },
76             })
77         } else {
78             None
79         }
80     }
81 }
82 
83 impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result84     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85         match self.try_lock() {
86             Some(guard) => write!(f, "Mutex {{ data: ")
87                 .and_then(|()| (&*guard).fmt(f))
88                 .and_then(|()| write!(f, "}}")),
89             None => write!(f, "Mutex {{ <locked> }}"),
90         }
91     }
92 }
93 
94 impl<T: ?Sized + Default> Default for Mutex<T> {
default() -> Mutex<T>95     fn default() -> Mutex<T> {
96         Mutex::new(Default::default())
97     }
98 }
99 
100 impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
101     type Target = T;
deref<'b>(&'b self) -> &'b T102     fn deref<'b>(&'b self) -> &'b T {
103         &*self.data
104     }
105 }
106 
107 impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
deref_mut<'b>(&'b mut self) -> &'b mut T108     fn deref_mut<'b>(&'b mut self) -> &'b mut T {
109         &mut *self.data
110     }
111 }
112 
113 impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
114     /// The dropping of the MutexGuard will release the lock it was created from.
drop(&mut self)115     fn drop(&mut self) {
116         self.lock.store(false, Ordering::Release);
117     }
118 }
119