]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/common/remutex.rs
core: Fix size_hint for signed integer Range<T> iterators
[rust.git] / src / libstd / sys / common / remutex.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 #![unstable(feature = "reentrant_mutex", reason = "new API")]
11
12 use prelude::v1::*;
13
14 use fmt;
15 use marker;
16 use ops::Deref;
17 use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
18 use sys::mutex as sys;
19
20 /// A re-entrant mutual exclusion
21 ///
22 /// This mutex will block *other* threads waiting for the lock to become available. The thread
23 /// which has already locked the mutex can lock it multiple times without blocking, preventing a
24 /// common source of deadlocks.
25 pub struct ReentrantMutex<T> {
26     inner: Box<sys::ReentrantMutex>,
27     poison: poison::Flag,
28     data: T,
29 }
30
31 unsafe impl<T: Send> Send for ReentrantMutex<T> {}
32 unsafe impl<T: Send> Sync for ReentrantMutex<T> {}
33
34
35 /// An RAII implementation of a "scoped lock" of a mutex. When this structure is
36 /// dropped (falls out of scope), the lock will be unlocked.
37 ///
38 /// The data protected by the mutex can be accessed through this guard via its
39 /// Deref and DerefMut implementations
40 #[must_use]
41 pub struct ReentrantMutexGuard<'a, T: 'a> {
42     // funny underscores due to how Deref/DerefMut currently work (they
43     // disregard field privacy).
44     __lock: &'a ReentrantMutex<T>,
45     __poison: poison::Guard,
46 }
47
48 impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {}
49
50
51 impl<T> ReentrantMutex<T> {
52     /// Creates a new reentrant mutex in an unlocked state.
53     pub fn new(t: T) -> ReentrantMutex<T> {
54         ReentrantMutex {
55             inner: box unsafe { sys::ReentrantMutex::new() },
56             poison: poison::FLAG_INIT,
57             data: t,
58         }
59     }
60
61     /// Acquires a mutex, blocking the current thread until it is able to do so.
62     ///
63     /// This function will block the caller until it is available to acquire the mutex.
64     /// Upon returning, the thread is the only thread with the mutex held. When the thread
65     /// calling this method already holds the lock, the call shall succeed without
66     /// blocking.
67     ///
68     /// # Failure
69     ///
70     /// If another user of this mutex panicked while holding the mutex, then
71     /// this call will return failure if the mutex would otherwise be
72     /// acquired.
73     pub fn lock(&self) -> LockResult<ReentrantMutexGuard<T>> {
74         unsafe { self.inner.lock() }
75         ReentrantMutexGuard::new(&self)
76     }
77
78     /// Attempts to acquire this lock.
79     ///
80     /// If the lock could not be acquired at this time, then `Err` is returned.
81     /// Otherwise, an RAII guard is returned.
82     ///
83     /// This function does not block.
84     ///
85     /// # Failure
86     ///
87     /// If another user of this mutex panicked while holding the mutex, then
88     /// this call will return failure if the mutex would otherwise be
89     /// acquired.
90     pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<T>> {
91         if unsafe { self.inner.try_lock() } {
92             Ok(try!(ReentrantMutexGuard::new(&self)))
93         } else {
94             Err(TryLockError::WouldBlock)
95         }
96     }
97 }
98
99 #[unsafe_destructor]
100 impl<T> Drop for ReentrantMutex<T> {
101     fn drop(&mut self) {
102         // This is actually safe b/c we know that there is no further usage of
103         // this mutex (it's up to the user to arrange for a mutex to get
104         // dropped, that's not our job)
105         unsafe { self.inner.destroy() }
106     }
107 }
108
109 impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
110     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111         match self.try_lock() {
112             Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
113             Err(TryLockError::Poisoned(err)) => {
114                 write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
115             },
116             Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
117         }
118     }
119 }
120
121 impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
122     fn new(lock: &'mutex ReentrantMutex<T>)
123             -> LockResult<ReentrantMutexGuard<'mutex, T>> {
124         poison::map_result(lock.poison.borrow(), |guard| {
125             ReentrantMutexGuard {
126                 __lock: lock,
127                 __poison: guard,
128             }
129         })
130     }
131 }
132
133 impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> {
134     type Target = T;
135
136     fn deref<'a>(&'a self) -> &'a T {
137         &self.__lock.data
138     }
139 }
140
141 #[unsafe_destructor]
142 impl<'a, T> Drop for ReentrantMutexGuard<'a, T> {
143     #[inline]
144     fn drop(&mut self) {
145         unsafe {
146             self.__lock.poison.done(&self.__poison);
147             self.__lock.inner.unlock();
148         }
149     }
150 }
151
152
153 #[cfg(test)]
154 mod test {
155     use prelude::v1::*;
156     use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
157     use cell::RefCell;
158     use sync::Arc;
159     use boxed;
160     use thread;
161
162     #[test]
163     fn smoke() {
164         let m = ReentrantMutex::new(());
165         {
166             let a = m.lock().unwrap();
167             {
168                 let b = m.lock().unwrap();
169                 {
170                     let c = m.lock().unwrap();
171                     assert_eq!(*c, ());
172                 }
173                 assert_eq!(*b, ());
174             }
175             assert_eq!(*a, ());
176         }
177     }
178
179     #[test]
180     fn is_mutex() {
181         let m = ReentrantMutex::new(RefCell::new(0));
182         let lock = m.lock().unwrap();
183         let handle = thread::scoped(|| {
184             let lock = m.lock().unwrap();
185             assert_eq!(*lock.borrow(), 4950);
186         });
187         for i in 0..100 {
188             let mut lock = m.lock().unwrap();
189             *lock.borrow_mut() += i;
190         }
191         drop(lock);
192         drop(handle);
193     }
194
195     #[test]
196     fn trylock_works() {
197         let m = ReentrantMutex::new(());
198         let lock = m.try_lock().unwrap();
199         let lock2 = m.try_lock().unwrap();
200         {
201             thread::scoped(|| {
202                 let lock = m.try_lock();
203                 assert!(lock.is_err());
204             });
205         }
206         let lock3 = m.try_lock().unwrap();
207     }
208
209     pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>);
210     impl<'a> Drop for Answer<'a> {
211         fn drop(&mut self) {
212             *self.0.borrow_mut() = 42;
213         }
214     }
215
216     #[test]
217     fn poison_works() {
218         let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
219         let mc = m.clone();
220         let result = thread::spawn(move ||{
221             let lock = mc.lock().unwrap();
222             *lock.borrow_mut() = 1;
223             let lock2 = mc.lock().unwrap();
224             *lock.borrow_mut() = 2;
225             let answer = Answer(lock2);
226             panic!("What the answer to my lifetimes dilemma is?");
227             drop(answer);
228         }).join();
229         assert!(result.is_err());
230         let r = m.lock().err().unwrap().into_inner();
231         assert_eq!(*r.borrow(), 42);
232     }
233 }