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