]>
Commit | Line | Data |
---|---|---|
9346a6ac AL |
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. | |
e9174d1e | 10 | |
9346a6ac AL |
11 | use prelude::v1::*; |
12 | ||
13 | use fmt; | |
14 | use marker; | |
15 | use ops::Deref; | |
16 | use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; | |
17 | use sys::mutex as sys; | |
18 | ||
19 | /// A re-entrant mutual exclusion | |
20 | /// | |
d9579d0f AL |
21 | /// This mutex will block *other* threads waiting for the lock to become |
22 | /// available. The thread which has already locked the mutex can lock it | |
23 | /// multiple times without blocking, preventing a common source of deadlocks. | |
9346a6ac AL |
24 | pub struct ReentrantMutex<T> { |
25 | inner: Box<sys::ReentrantMutex>, | |
26 | poison: poison::Flag, | |
27 | data: T, | |
28 | } | |
29 | ||
30 | unsafe impl<T: Send> Send for ReentrantMutex<T> {} | |
31 | unsafe impl<T: Send> Sync for ReentrantMutex<T> {} | |
32 | ||
33 | ||
34 | /// An RAII implementation of a "scoped lock" of a mutex. When this structure is | |
35 | /// dropped (falls out of scope), the lock will be unlocked. | |
36 | /// | |
37 | /// The data protected by the mutex can be accessed through this guard via its | |
e9174d1e SL |
38 | /// Deref implementation. |
39 | /// | |
40 | /// # Mutability | |
41 | /// | |
42 | /// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`, | |
43 | /// because implementation of the trait would violate Rust’s reference aliasing | |
44 | /// rules. Use interior mutability (usually `RefCell`) in order to mutate the | |
45 | /// guarded data. | |
9346a6ac AL |
46 | #[must_use] |
47 | pub struct ReentrantMutexGuard<'a, T: 'a> { | |
e9174d1e SL |
48 | // funny underscores due to how Deref currently works (it disregards field |
49 | // privacy). | |
9346a6ac AL |
50 | __lock: &'a ReentrantMutex<T>, |
51 | __poison: poison::Guard, | |
52 | } | |
53 | ||
54 | impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {} | |
55 | ||
56 | ||
57 | impl<T> ReentrantMutex<T> { | |
58 | /// Creates a new reentrant mutex in an unlocked state. | |
59 | pub fn new(t: T) -> ReentrantMutex<T> { | |
d9579d0f AL |
60 | unsafe { |
61 | let mut mutex = ReentrantMutex { | |
62 | inner: box sys::ReentrantMutex::uninitialized(), | |
62682a34 | 63 | poison: poison::Flag::new(), |
d9579d0f AL |
64 | data: t, |
65 | }; | |
66 | mutex.inner.init(); | |
e9174d1e | 67 | mutex |
9346a6ac AL |
68 | } |
69 | } | |
70 | ||
71 | /// Acquires a mutex, blocking the current thread until it is able to do so. | |
72 | /// | |
73 | /// This function will block the caller until it is available to acquire the mutex. | |
74 | /// Upon returning, the thread is the only thread with the mutex held. When the thread | |
75 | /// calling this method already holds the lock, the call shall succeed without | |
76 | /// blocking. | |
77 | /// | |
7453a54e | 78 | /// # Errors |
9346a6ac AL |
79 | /// |
80 | /// If another user of this mutex panicked while holding the mutex, then | |
81 | /// this call will return failure if the mutex would otherwise be | |
82 | /// acquired. | |
83 | pub fn lock(&self) -> LockResult<ReentrantMutexGuard<T>> { | |
84 | unsafe { self.inner.lock() } | |
85 | ReentrantMutexGuard::new(&self) | |
86 | } | |
87 | ||
88 | /// Attempts to acquire this lock. | |
89 | /// | |
90 | /// If the lock could not be acquired at this time, then `Err` is returned. | |
91 | /// Otherwise, an RAII guard is returned. | |
92 | /// | |
93 | /// This function does not block. | |
94 | /// | |
7453a54e | 95 | /// # Errors |
9346a6ac AL |
96 | /// |
97 | /// If another user of this mutex panicked while holding the mutex, then | |
98 | /// this call will return failure if the mutex would otherwise be | |
99 | /// acquired. | |
100 | pub fn try_lock(&self) -> TryLockResult<ReentrantMutexGuard<T>> { | |
101 | if unsafe { self.inner.try_lock() } { | |
54a0048b | 102 | Ok(ReentrantMutexGuard::new(&self)?) |
9346a6ac AL |
103 | } else { |
104 | Err(TryLockError::WouldBlock) | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
9346a6ac AL |
109 | impl<T> Drop for ReentrantMutex<T> { |
110 | fn drop(&mut self) { | |
111 | // This is actually safe b/c we know that there is no further usage of | |
112 | // this mutex (it's up to the user to arrange for a mutex to get | |
113 | // dropped, that's not our job) | |
114 | unsafe { self.inner.destroy() } | |
115 | } | |
116 | } | |
117 | ||
118 | impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> { | |
119 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
120 | match self.try_lock() { | |
121 | Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard), | |
122 | Err(TryLockError::Poisoned(err)) => { | |
123 | write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) | |
124 | }, | |
125 | Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}") | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { | |
131 | fn new(lock: &'mutex ReentrantMutex<T>) | |
132 | -> LockResult<ReentrantMutexGuard<'mutex, T>> { | |
133 | poison::map_result(lock.poison.borrow(), |guard| { | |
134 | ReentrantMutexGuard { | |
135 | __lock: lock, | |
136 | __poison: guard, | |
137 | } | |
138 | }) | |
139 | } | |
140 | } | |
141 | ||
142 | impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> { | |
143 | type Target = T; | |
144 | ||
e9174d1e | 145 | fn deref(&self) -> &T { |
9346a6ac AL |
146 | &self.__lock.data |
147 | } | |
148 | } | |
149 | ||
9346a6ac AL |
150 | impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { |
151 | #[inline] | |
152 | fn drop(&mut self) { | |
153 | unsafe { | |
154 | self.__lock.poison.done(&self.__poison); | |
155 | self.__lock.inner.unlock(); | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | ||
161 | #[cfg(test)] | |
d9579d0f | 162 | mod tests { |
9346a6ac AL |
163 | use prelude::v1::*; |
164 | use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; | |
165 | use cell::RefCell; | |
166 | use sync::Arc; | |
9346a6ac AL |
167 | use thread; |
168 | ||
169 | #[test] | |
170 | fn smoke() { | |
171 | let m = ReentrantMutex::new(()); | |
172 | { | |
173 | let a = m.lock().unwrap(); | |
174 | { | |
175 | let b = m.lock().unwrap(); | |
176 | { | |
177 | let c = m.lock().unwrap(); | |
178 | assert_eq!(*c, ()); | |
179 | } | |
180 | assert_eq!(*b, ()); | |
181 | } | |
182 | assert_eq!(*a, ()); | |
183 | } | |
184 | } | |
185 | ||
186 | #[test] | |
187 | fn is_mutex() { | |
e9174d1e SL |
188 | let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); |
189 | let m2 = m.clone(); | |
9346a6ac | 190 | let lock = m.lock().unwrap(); |
e9174d1e SL |
191 | let child = thread::spawn(move || { |
192 | let lock = m2.lock().unwrap(); | |
9346a6ac AL |
193 | assert_eq!(*lock.borrow(), 4950); |
194 | }); | |
195 | for i in 0..100 { | |
62682a34 | 196 | let lock = m.lock().unwrap(); |
9346a6ac AL |
197 | *lock.borrow_mut() += i; |
198 | } | |
199 | drop(lock); | |
e9174d1e | 200 | child.join().unwrap(); |
9346a6ac AL |
201 | } |
202 | ||
203 | #[test] | |
204 | fn trylock_works() { | |
e9174d1e SL |
205 | let m = Arc::new(ReentrantMutex::new(())); |
206 | let m2 = m.clone(); | |
9cc50fc6 SL |
207 | let _lock = m.try_lock().unwrap(); |
208 | let _lock2 = m.try_lock().unwrap(); | |
e9174d1e SL |
209 | thread::spawn(move || { |
210 | let lock = m2.try_lock(); | |
211 | assert!(lock.is_err()); | |
212 | }).join().unwrap(); | |
9cc50fc6 | 213 | let _lock3 = m.try_lock().unwrap(); |
9346a6ac AL |
214 | } |
215 | ||
216 | pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell<u32>>); | |
217 | impl<'a> Drop for Answer<'a> { | |
218 | fn drop(&mut self) { | |
219 | *self.0.borrow_mut() = 42; | |
220 | } | |
221 | } | |
222 | ||
223 | #[test] | |
224 | fn poison_works() { | |
225 | let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); | |
226 | let mc = m.clone(); | |
227 | let result = thread::spawn(move ||{ | |
228 | let lock = mc.lock().unwrap(); | |
229 | *lock.borrow_mut() = 1; | |
230 | let lock2 = mc.lock().unwrap(); | |
231 | *lock.borrow_mut() = 2; | |
9cc50fc6 | 232 | let _answer = Answer(lock2); |
9346a6ac | 233 | panic!("What the answer to my lifetimes dilemma is?"); |
9346a6ac AL |
234 | }).join(); |
235 | assert!(result.is_err()); | |
236 | let r = m.lock().err().unwrap().into_inner(); | |
237 | assert_eq!(*r.borrow(), 42); | |
238 | } | |
239 | } |