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