1 //! A "mutex" which only supports `try_lock` 2 //! 3 //! As a futures library the eventual call to an event loop should be the only 4 //! thing that ever blocks, so this is assisted with a fast user-space 5 //! implementation of a lock that can only have a `try_lock` operation. 6 7 use core::cell::UnsafeCell; 8 use core::ops::{Deref, DerefMut}; 9 use core::sync::atomic::AtomicBool; 10 use core::sync::atomic::Ordering::SeqCst; 11 12 /// A "mutex" around a value, similar to `std::sync::Mutex<T>`. 13 /// 14 /// This lock only supports the `try_lock` operation, however, and does not 15 /// implement poisoning. 16 #[derive(Debug)] 17 pub(crate) struct Lock<T> { 18 locked: AtomicBool, 19 data: UnsafeCell<T>, 20 } 21 22 /// Sentinel representing an acquired lock through which the data can be 23 /// accessed. 24 pub(crate) struct TryLock<'a, T> { 25 __ptr: &'a Lock<T>, 26 } 27 28 // The `Lock` structure is basically just a `Mutex<T>`, and these two impls are 29 // intended to mirror the standard library's corresponding impls for `Mutex<T>`. 30 // 31 // If a `T` is sendable across threads, so is the lock, and `T` must be sendable 32 // across threads to be `Sync` because it allows mutable access from multiple 33 // threads. 34 unsafe impl<T: Send> Send for Lock<T> {} 35 unsafe impl<T: Send> Sync for Lock<T> {} 36 37 impl<T> Lock<T> { 38 /// Creates a new lock around the given value. new(t: T) -> Self39 pub(crate) fn new(t: T) -> Self { 40 Self { locked: AtomicBool::new(false), data: UnsafeCell::new(t) } 41 } 42 43 /// Attempts to acquire this lock, returning whether the lock was acquired or 44 /// not. 45 /// 46 /// If `Some` is returned then the data this lock protects can be accessed 47 /// through the sentinel. This sentinel allows both mutable and immutable 48 /// access. 49 /// 50 /// If `None` is returned then the lock is already locked, either elsewhere 51 /// on this thread or on another thread. try_lock(&self) -> Option<TryLock<'_, T>>52 pub(crate) fn try_lock(&self) -> Option<TryLock<'_, T>> { 53 if !self.locked.swap(true, SeqCst) { 54 Some(TryLock { __ptr: self }) 55 } else { 56 None 57 } 58 } 59 } 60 61 impl<T> Deref for TryLock<'_, T> { 62 type Target = T; deref(&self) -> &T63 fn deref(&self) -> &T { 64 // The existence of `TryLock` represents that we own the lock, so we 65 // can safely access the data here. 66 unsafe { &*self.__ptr.data.get() } 67 } 68 } 69 70 impl<T> DerefMut for TryLock<'_, T> { deref_mut(&mut self) -> &mut T71 fn deref_mut(&mut self) -> &mut T { 72 // The existence of `TryLock` represents that we own the lock, so we 73 // can safely access the data here. 74 // 75 // Additionally, we're the *only* `TryLock` in existence so mutable 76 // access should be ok. 77 unsafe { &mut *self.__ptr.data.get() } 78 } 79 } 80 81 impl<T> Drop for TryLock<'_, T> { drop(&mut self)82 fn drop(&mut self) { 83 self.__ptr.locked.store(false, SeqCst); 84 } 85 } 86 87 #[cfg(test)] 88 mod tests { 89 use super::Lock; 90 91 #[test] smoke()92 fn smoke() { 93 let a = Lock::new(1); 94 let mut a1 = a.try_lock().unwrap(); 95 assert!(a.try_lock().is_none()); 96 assert_eq!(*a1, 1); 97 *a1 = 2; 98 drop(a1); 99 assert_eq!(*a.try_lock().unwrap(), 2); 100 assert_eq!(*a.try_lock().unwrap(), 2); 101 } 102 } 103