]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | ||
1a4d82fc | 11 | use cell::UnsafeCell; |
9346a6ac | 12 | use fmt; |
1a4d82fc | 13 | use marker; |
b039eaaf | 14 | use mem; |
1a4d82fc | 15 | use ops::{Deref, DerefMut}; |
b039eaaf | 16 | use ptr; |
1a4d82fc | 17 | use sys_common::mutex as sys; |
9346a6ac | 18 | use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; |
1a4d82fc JJ |
19 | |
20 | /// A mutual exclusion primitive useful for protecting shared data | |
21 | /// | |
22 | /// This mutex will block threads waiting for the lock to become available. The | |
23 | /// mutex can also be statically initialized or created via a `new` | |
24 | /// constructor. Each mutex has a type parameter which represents the data that | |
25 | /// it is protecting. The data can only be accessed through the RAII guards | |
26 | /// returned from `lock` and `try_lock`, which guarantees that the data is only | |
27 | /// ever accessed when the mutex is locked. | |
28 | /// | |
29 | /// # Poisoning | |
30 | /// | |
31 | /// The mutexes in this module implement a strategy called "poisoning" where a | |
32 | /// mutex is considered poisoned whenever a thread panics while holding the | |
bd371182 | 33 | /// lock. Once a mutex is poisoned, all other threads are unable to access the |
1a4d82fc JJ |
34 | /// data by default as it is likely tainted (some invariant is not being |
35 | /// upheld). | |
36 | /// | |
37 | /// For a mutex, this means that the `lock` and `try_lock` methods return a | |
38 | /// `Result` which indicates whether a mutex has been poisoned or not. Most | |
39 | /// usage of a mutex will simply `unwrap()` these results, propagating panics | |
40 | /// among threads to ensure that a possibly invalid invariant is not witnessed. | |
41 | /// | |
42 | /// A poisoned mutex, however, does not prevent all access to the underlying | |
c34b1796 | 43 | /// data. The `PoisonError` type has an `into_inner` method which will return |
1a4d82fc JJ |
44 | /// the guard that would have otherwise been returned on a successful lock. This |
45 | /// allows access to the data, despite the lock being poisoned. | |
46 | /// | |
47 | /// # Examples | |
48 | /// | |
c34b1796 | 49 | /// ``` |
1a4d82fc | 50 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 51 | /// use std::thread; |
1a4d82fc JJ |
52 | /// use std::sync::mpsc::channel; |
53 | /// | |
c34b1796 | 54 | /// const N: usize = 10; |
1a4d82fc JJ |
55 | /// |
56 | /// // Spawn a few threads to increment a shared variable (non-atomically), and | |
57 | /// // let the main thread know once all increments are done. | |
58 | /// // | |
bd371182 | 59 | /// // Here we're using an Arc to share memory among threads, and the data inside |
1a4d82fc JJ |
60 | /// // the Arc is protected with a mutex. |
61 | /// let data = Arc::new(Mutex::new(0)); | |
62 | /// | |
63 | /// let (tx, rx) = channel(); | |
85aaf69f | 64 | /// for _ in 0..10 { |
1a4d82fc | 65 | /// let (data, tx) = (data.clone(), tx.clone()); |
85aaf69f | 66 | /// thread::spawn(move || { |
92a42be0 | 67 | /// // The shared state can only be accessed once the lock is held. |
1a4d82fc JJ |
68 | /// // Our non-atomic increment is safe because we're the only thread |
69 | /// // which can access the shared state when the lock is held. | |
70 | /// // | |
71 | /// // We unwrap() the return value to assert that we are not expecting | |
bd371182 | 72 | /// // threads to ever fail while holding the lock. |
1a4d82fc JJ |
73 | /// let mut data = data.lock().unwrap(); |
74 | /// *data += 1; | |
75 | /// if *data == N { | |
76 | /// tx.send(()).unwrap(); | |
77 | /// } | |
78 | /// // the lock is unlocked here when `data` goes out of scope. | |
79 | /// }); | |
80 | /// } | |
81 | /// | |
82 | /// rx.recv().unwrap(); | |
83 | /// ``` | |
84 | /// | |
85 | /// To recover from a poisoned mutex: | |
86 | /// | |
c34b1796 | 87 | /// ``` |
1a4d82fc | 88 | /// use std::sync::{Arc, Mutex}; |
85aaf69f | 89 | /// use std::thread; |
1a4d82fc | 90 | /// |
85aaf69f | 91 | /// let lock = Arc::new(Mutex::new(0_u32)); |
1a4d82fc JJ |
92 | /// let lock2 = lock.clone(); |
93 | /// | |
85aaf69f | 94 | /// let _ = thread::spawn(move || -> () { |
1a4d82fc JJ |
95 | /// // This thread will acquire the mutex first, unwrapping the result of |
96 | /// // `lock` because the lock has not been poisoned. | |
7453a54e | 97 | /// let _guard = lock2.lock().unwrap(); |
1a4d82fc JJ |
98 | /// |
99 | /// // This panic while holding the lock (`_guard` is in scope) will poison | |
100 | /// // the mutex. | |
101 | /// panic!(); | |
102 | /// }).join(); | |
103 | /// | |
104 | /// // The lock is poisoned by this point, but the returned result can be | |
105 | /// // pattern matched on to return the underlying guard on both branches. | |
106 | /// let mut guard = match lock.lock() { | |
107 | /// Ok(guard) => guard, | |
c34b1796 | 108 | /// Err(poisoned) => poisoned.into_inner(), |
1a4d82fc JJ |
109 | /// }; |
110 | /// | |
111 | /// *guard += 1; | |
112 | /// ``` | |
85aaf69f | 113 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 114 | pub struct Mutex<T: ?Sized> { |
5bcae85e SL |
115 | // Note that this mutex is in a *box*, not inlined into the struct itself. |
116 | // Once a native mutex has been used once, its address can never change (it | |
117 | // can't be moved). This mutex type can be safely moved at any time, so to | |
118 | // ensure that the native mutex is used correctly we box the inner lock to | |
119 | // give it a constant address. | |
120 | inner: Box<sys::Mutex>, | |
121 | poison: poison::Flag, | |
1a4d82fc JJ |
122 | data: UnsafeCell<T>, |
123 | } | |
124 | ||
c34b1796 AL |
125 | // these are the only places where `T: Send` matters; all other |
126 | // functionality works fine on a single thread. | |
92a42be0 | 127 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 128 | unsafe impl<T: ?Sized + Send> Send for Mutex<T> { } |
92a42be0 | 129 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 130 | unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { } |
1a4d82fc | 131 | |
1a4d82fc JJ |
132 | /// An RAII implementation of a "scoped lock" of a mutex. When this structure is |
133 | /// dropped (falls out of scope), the lock will be unlocked. | |
134 | /// | |
135 | /// The data protected by the mutex can be access through this guard via its | |
d9579d0f | 136 | /// `Deref` and `DerefMut` implementations |
1a4d82fc | 137 | #[must_use] |
85aaf69f | 138 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 139 | pub struct MutexGuard<'a, T: ?Sized + 'a> { |
1a4d82fc JJ |
140 | // funny underscores due to how Deref/DerefMut currently work (they |
141 | // disregard field privacy). | |
5bcae85e | 142 | __lock: &'a Mutex<T>, |
1a4d82fc | 143 | __poison: poison::Guard, |
1a4d82fc JJ |
144 | } |
145 | ||
92a42be0 | 146 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 147 | impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} |
85aaf69f | 148 | |
c34b1796 | 149 | impl<T> Mutex<T> { |
1a4d82fc | 150 | /// Creates a new mutex in an unlocked state ready for use. |
85aaf69f | 151 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 152 | pub fn new(t: T) -> Mutex<T> { |
3157f602 | 153 | let mut m = Mutex { |
5bcae85e SL |
154 | inner: box sys::Mutex::new(), |
155 | poison: poison::Flag::new(), | |
1a4d82fc | 156 | data: UnsafeCell::new(t), |
3157f602 XL |
157 | }; |
158 | unsafe { | |
5bcae85e | 159 | m.inner.init(); |
1a4d82fc | 160 | } |
3157f602 | 161 | m |
1a4d82fc | 162 | } |
d9579d0f | 163 | } |
1a4d82fc | 164 | |
d9579d0f | 165 | impl<T: ?Sized> Mutex<T> { |
bd371182 | 166 | /// Acquires a mutex, blocking the current thread until it is able to do so. |
1a4d82fc | 167 | /// |
bd371182 AL |
168 | /// This function will block the local thread until it is available to acquire |
169 | /// the mutex. Upon returning, the thread is the only thread with the mutex | |
1a4d82fc JJ |
170 | /// held. An RAII guard is returned to allow scoped unlock of the lock. When |
171 | /// the guard goes out of scope, the mutex will be unlocked. | |
172 | /// | |
a7813a04 XL |
173 | /// The exact behavior on locking a mutex in the thread which already holds |
174 | /// the lock is left unspecified. However, this function will not return on | |
175 | /// the second call (it might panic or deadlock, for example). | |
176 | /// | |
7453a54e | 177 | /// # Errors |
1a4d82fc JJ |
178 | /// |
179 | /// If another user of this mutex panicked while holding the mutex, then | |
180 | /// this call will return an error once the mutex is acquired. | |
a7813a04 XL |
181 | /// |
182 | /// # Panics | |
183 | /// | |
184 | /// This function might panic when called if the lock is already held by | |
185 | /// the current thread. | |
85aaf69f | 186 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 187 | pub fn lock(&self) -> LockResult<MutexGuard<T>> { |
7453a54e | 188 | unsafe { |
5bcae85e SL |
189 | self.inner.lock(); |
190 | MutexGuard::new(self) | |
7453a54e | 191 | } |
1a4d82fc JJ |
192 | } |
193 | ||
194 | /// Attempts to acquire this lock. | |
195 | /// | |
9346a6ac | 196 | /// If the lock could not be acquired at this time, then `Err` is returned. |
1a4d82fc JJ |
197 | /// Otherwise, an RAII guard is returned. The lock will be unlocked when the |
198 | /// guard is dropped. | |
199 | /// | |
200 | /// This function does not block. | |
201 | /// | |
7453a54e | 202 | /// # Errors |
1a4d82fc JJ |
203 | /// |
204 | /// If another user of this mutex panicked while holding the mutex, then | |
205 | /// this call will return failure if the mutex would otherwise be | |
206 | /// acquired. | |
85aaf69f | 207 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 208 | pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> { |
7453a54e | 209 | unsafe { |
5bcae85e SL |
210 | if self.inner.try_lock() { |
211 | Ok(MutexGuard::new(self)?) | |
7453a54e SL |
212 | } else { |
213 | Err(TryLockError::WouldBlock) | |
214 | } | |
1a4d82fc JJ |
215 | } |
216 | } | |
85aaf69f | 217 | |
9346a6ac | 218 | /// Determines whether the lock is poisoned. |
85aaf69f SL |
219 | /// |
220 | /// If another thread is active, the lock can still become poisoned at any | |
221 | /// time. You should not trust a `false` value for program correctness | |
222 | /// without additional synchronization. | |
223 | #[inline] | |
62682a34 | 224 | #[stable(feature = "sync_poison", since = "1.2.0")] |
85aaf69f | 225 | pub fn is_poisoned(&self) -> bool { |
5bcae85e | 226 | self.poison.get() |
85aaf69f | 227 | } |
b039eaaf SL |
228 | |
229 | /// Consumes this mutex, returning the underlying data. | |
230 | /// | |
7453a54e | 231 | /// # Errors |
b039eaaf SL |
232 | /// |
233 | /// If another user of this mutex panicked while holding the mutex, then | |
234 | /// this call will return an error instead. | |
92a42be0 | 235 | #[stable(feature = "mutex_into_inner", since = "1.6.0")] |
b039eaaf SL |
236 | pub fn into_inner(self) -> LockResult<T> where T: Sized { |
237 | // We know statically that there are no outstanding references to | |
5bcae85e | 238 | // `self` so there's no need to lock the inner lock. |
b039eaaf SL |
239 | // |
240 | // To get the inner value, we'd like to call `data.into_inner()`, | |
241 | // but because `Mutex` impl-s `Drop`, we can't move out of it, so | |
242 | // we'll have to destructure it manually instead. | |
243 | unsafe { | |
5bcae85e SL |
244 | // Like `let Mutex { inner, poison, data } = self`. |
245 | let (inner, poison, data) = { | |
246 | let Mutex { ref inner, ref poison, ref data } = self; | |
247 | (ptr::read(inner), ptr::read(poison), ptr::read(data)) | |
b039eaaf SL |
248 | }; |
249 | mem::forget(self); | |
5bcae85e SL |
250 | inner.destroy(); // Keep in sync with the `Drop` impl. |
251 | drop(inner); | |
b039eaaf | 252 | |
5bcae85e | 253 | poison::map_result(poison.borrow(), |_| data.into_inner()) |
b039eaaf SL |
254 | } |
255 | } | |
256 | ||
257 | /// Returns a mutable reference to the underlying data. | |
258 | /// | |
259 | /// Since this call borrows the `Mutex` mutably, no actual locking needs to | |
260 | /// take place---the mutable borrow statically guarantees no locks exist. | |
261 | /// | |
7453a54e | 262 | /// # Errors |
b039eaaf SL |
263 | /// |
264 | /// If another user of this mutex panicked while holding the mutex, then | |
265 | /// this call will return an error instead. | |
92a42be0 | 266 | #[stable(feature = "mutex_get_mut", since = "1.6.0")] |
b039eaaf SL |
267 | pub fn get_mut(&mut self) -> LockResult<&mut T> { |
268 | // We know statically that there are no other references to `self`, so | |
5bcae85e | 269 | // there's no need to lock the inner lock. |
b039eaaf | 270 | let data = unsafe { &mut *self.data.get() }; |
5bcae85e | 271 | poison::map_result(self.poison.borrow(), |_| data ) |
b039eaaf | 272 | } |
1a4d82fc JJ |
273 | } |
274 | ||
85aaf69f | 275 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 276 | impl<T: ?Sized> Drop for Mutex<T> { |
b039eaaf | 277 | #[unsafe_destructor_blind_to_params] |
1a4d82fc JJ |
278 | fn drop(&mut self) { |
279 | // This is actually safe b/c we know that there is no further usage of | |
280 | // this mutex (it's up to the user to arrange for a mutex to get | |
281 | // dropped, that's not our job) | |
b039eaaf SL |
282 | // |
283 | // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. | |
5bcae85e | 284 | unsafe { self.inner.destroy() } |
1a4d82fc JJ |
285 | } |
286 | } | |
287 | ||
a7813a04 XL |
288 | #[stable(feature = "mutex_default", since = "1.9.0")] |
289 | impl<T: ?Sized + Default> Default for Mutex<T> { | |
9e0c209e | 290 | /// Creates a `Mutex<T>`, with the `Default` value for T. |
a7813a04 XL |
291 | fn default() -> Mutex<T> { |
292 | Mutex::new(Default::default()) | |
293 | } | |
294 | } | |
295 | ||
c34b1796 | 296 | #[stable(feature = "rust1", since = "1.0.0")] |
7453a54e | 297 | impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { |
c34b1796 AL |
298 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
299 | match self.try_lock() { | |
d9579d0f | 300 | Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard), |
c34b1796 | 301 | Err(TryLockError::Poisoned(err)) => { |
d9579d0f | 302 | write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) |
c34b1796 AL |
303 | }, |
304 | Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}") | |
305 | } | |
306 | } | |
307 | } | |
308 | ||
d9579d0f | 309 | impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { |
5bcae85e | 310 | unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> { |
1a4d82fc JJ |
311 | poison::map_result(lock.poison.borrow(), |guard| { |
312 | MutexGuard { | |
313 | __lock: lock, | |
1a4d82fc | 314 | __poison: guard, |
1a4d82fc JJ |
315 | } |
316 | }) | |
317 | } | |
318 | } | |
319 | ||
85aaf69f | 320 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 321 | impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> { |
1a4d82fc JJ |
322 | type Target = T; |
323 | ||
5bcae85e SL |
324 | fn deref(&self) -> &T { |
325 | unsafe { &*self.__lock.data.get() } | |
326 | } | |
1a4d82fc | 327 | } |
e9174d1e | 328 | |
85aaf69f | 329 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 330 | impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> { |
5bcae85e SL |
331 | fn deref_mut(&mut self) -> &mut T { |
332 | unsafe { &mut *self.__lock.data.get() } | |
333 | } | |
1a4d82fc JJ |
334 | } |
335 | ||
85aaf69f | 336 | #[stable(feature = "rust1", since = "1.0.0")] |
d9579d0f | 337 | impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { |
1a4d82fc JJ |
338 | #[inline] |
339 | fn drop(&mut self) { | |
340 | unsafe { | |
341 | self.__lock.poison.done(&self.__poison); | |
5bcae85e | 342 | self.__lock.inner.unlock(); |
1a4d82fc JJ |
343 | } |
344 | } | |
345 | } | |
346 | ||
d9579d0f | 347 | pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { |
5bcae85e | 348 | &guard.__lock.inner |
1a4d82fc JJ |
349 | } |
350 | ||
d9579d0f | 351 | pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { |
1a4d82fc JJ |
352 | &guard.__lock.poison |
353 | } | |
354 | ||
355 | #[cfg(test)] | |
d9579d0f | 356 | mod tests { |
1a4d82fc | 357 | use sync::mpsc::channel; |
5bcae85e | 358 | use sync::{Arc, Mutex, Condvar}; |
b039eaaf | 359 | use sync::atomic::{AtomicUsize, Ordering}; |
85aaf69f | 360 | use thread; |
1a4d82fc | 361 | |
e9174d1e | 362 | struct Packet<T>(Arc<(Mutex<T>, Condvar)>); |
1a4d82fc | 363 | |
b039eaaf SL |
364 | #[derive(Eq, PartialEq, Debug)] |
365 | struct NonCopy(i32); | |
366 | ||
c34b1796 | 367 | unsafe impl<T: Send> Send for Packet<T> {} |
1a4d82fc JJ |
368 | unsafe impl<T> Sync for Packet<T> {} |
369 | ||
370 | #[test] | |
371 | fn smoke() { | |
372 | let m = Mutex::new(()); | |
373 | drop(m.lock().unwrap()); | |
374 | drop(m.lock().unwrap()); | |
375 | } | |
376 | ||
1a4d82fc JJ |
377 | #[test] |
378 | fn lots_and_lots() { | |
c34b1796 AL |
379 | const J: u32 = 1000; |
380 | const K: u32 = 3; | |
1a4d82fc | 381 | |
5bcae85e SL |
382 | let m = Arc::new(Mutex::new(0)); |
383 | ||
384 | fn inc(m: &Mutex<u32>) { | |
85aaf69f | 385 | for _ in 0..J { |
5bcae85e | 386 | *m.lock().unwrap() += 1; |
1a4d82fc JJ |
387 | } |
388 | } | |
389 | ||
390 | let (tx, rx) = channel(); | |
85aaf69f | 391 | for _ in 0..K { |
1a4d82fc | 392 | let tx2 = tx.clone(); |
5bcae85e SL |
393 | let m2 = m.clone(); |
394 | thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); | |
1a4d82fc | 395 | let tx2 = tx.clone(); |
5bcae85e SL |
396 | let m2 = m.clone(); |
397 | thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); }); | |
1a4d82fc JJ |
398 | } |
399 | ||
400 | drop(tx); | |
85aaf69f | 401 | for _ in 0..2 * K { |
1a4d82fc JJ |
402 | rx.recv().unwrap(); |
403 | } | |
5bcae85e | 404 | assert_eq!(*m.lock().unwrap(), J * K * 2); |
1a4d82fc JJ |
405 | } |
406 | ||
407 | #[test] | |
408 | fn try_lock() { | |
409 | let m = Mutex::new(()); | |
410 | *m.try_lock().unwrap() = (); | |
411 | } | |
412 | ||
b039eaaf SL |
413 | #[test] |
414 | fn test_into_inner() { | |
415 | let m = Mutex::new(NonCopy(10)); | |
416 | assert_eq!(m.into_inner().unwrap(), NonCopy(10)); | |
417 | } | |
418 | ||
419 | #[test] | |
420 | fn test_into_inner_drop() { | |
421 | struct Foo(Arc<AtomicUsize>); | |
422 | impl Drop for Foo { | |
423 | fn drop(&mut self) { | |
424 | self.0.fetch_add(1, Ordering::SeqCst); | |
425 | } | |
426 | } | |
427 | let num_drops = Arc::new(AtomicUsize::new(0)); | |
428 | let m = Mutex::new(Foo(num_drops.clone())); | |
429 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
430 | { | |
431 | let _inner = m.into_inner().unwrap(); | |
432 | assert_eq!(num_drops.load(Ordering::SeqCst), 0); | |
433 | } | |
434 | assert_eq!(num_drops.load(Ordering::SeqCst), 1); | |
435 | } | |
436 | ||
437 | #[test] | |
438 | fn test_into_inner_poison() { | |
439 | let m = Arc::new(Mutex::new(NonCopy(10))); | |
440 | let m2 = m.clone(); | |
441 | let _ = thread::spawn(move || { | |
442 | let _lock = m2.lock().unwrap(); | |
443 | panic!("test panic in inner thread to poison mutex"); | |
444 | }).join(); | |
445 | ||
446 | assert!(m.is_poisoned()); | |
447 | match Arc::try_unwrap(m).unwrap().into_inner() { | |
448 | Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), | |
449 | Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), | |
450 | } | |
451 | } | |
452 | ||
453 | #[test] | |
454 | fn test_get_mut() { | |
455 | let mut m = Mutex::new(NonCopy(10)); | |
456 | *m.get_mut().unwrap() = NonCopy(20); | |
457 | assert_eq!(m.into_inner().unwrap(), NonCopy(20)); | |
458 | } | |
459 | ||
460 | #[test] | |
461 | fn test_get_mut_poison() { | |
462 | let m = Arc::new(Mutex::new(NonCopy(10))); | |
463 | let m2 = m.clone(); | |
464 | let _ = thread::spawn(move || { | |
465 | let _lock = m2.lock().unwrap(); | |
466 | panic!("test panic in inner thread to poison mutex"); | |
467 | }).join(); | |
468 | ||
469 | assert!(m.is_poisoned()); | |
470 | match Arc::try_unwrap(m).unwrap().get_mut() { | |
471 | Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), | |
472 | Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), | |
473 | } | |
474 | } | |
475 | ||
1a4d82fc JJ |
476 | #[test] |
477 | fn test_mutex_arc_condvar() { | |
478 | let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); | |
479 | let packet2 = Packet(packet.0.clone()); | |
480 | let (tx, rx) = channel(); | |
85aaf69f | 481 | let _t = thread::spawn(move|| { |
1a4d82fc JJ |
482 | // wait until parent gets in |
483 | rx.recv().unwrap(); | |
484 | let &(ref lock, ref cvar) = &*packet2.0; | |
485 | let mut lock = lock.lock().unwrap(); | |
486 | *lock = true; | |
487 | cvar.notify_one(); | |
488 | }); | |
489 | ||
490 | let &(ref lock, ref cvar) = &*packet.0; | |
491 | let mut lock = lock.lock().unwrap(); | |
492 | tx.send(()).unwrap(); | |
493 | assert!(!*lock); | |
494 | while !*lock { | |
495 | lock = cvar.wait(lock).unwrap(); | |
496 | } | |
497 | } | |
498 | ||
499 | #[test] | |
500 | fn test_arc_condvar_poison() { | |
85aaf69f | 501 | let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); |
1a4d82fc JJ |
502 | let packet2 = Packet(packet.0.clone()); |
503 | let (tx, rx) = channel(); | |
504 | ||
85aaf69f | 505 | let _t = thread::spawn(move || -> () { |
1a4d82fc JJ |
506 | rx.recv().unwrap(); |
507 | let &(ref lock, ref cvar) = &*packet2.0; | |
508 | let _g = lock.lock().unwrap(); | |
509 | cvar.notify_one(); | |
510 | // Parent should fail when it wakes up. | |
511 | panic!(); | |
512 | }); | |
513 | ||
514 | let &(ref lock, ref cvar) = &*packet.0; | |
515 | let mut lock = lock.lock().unwrap(); | |
516 | tx.send(()).unwrap(); | |
517 | while *lock == 1 { | |
518 | match cvar.wait(lock) { | |
519 | Ok(l) => { | |
520 | lock = l; | |
521 | assert_eq!(*lock, 1); | |
522 | } | |
523 | Err(..) => break, | |
524 | } | |
525 | } | |
526 | } | |
527 | ||
528 | #[test] | |
529 | fn test_mutex_arc_poison() { | |
85aaf69f SL |
530 | let arc = Arc::new(Mutex::new(1)); |
531 | assert!(!arc.is_poisoned()); | |
1a4d82fc | 532 | let arc2 = arc.clone(); |
85aaf69f | 533 | let _ = thread::spawn(move|| { |
1a4d82fc JJ |
534 | let lock = arc2.lock().unwrap(); |
535 | assert_eq!(*lock, 2); | |
536 | }).join(); | |
537 | assert!(arc.lock().is_err()); | |
85aaf69f | 538 | assert!(arc.is_poisoned()); |
1a4d82fc JJ |
539 | } |
540 | ||
541 | #[test] | |
542 | fn test_mutex_arc_nested() { | |
543 | // Tests nested mutexes and access | |
544 | // to underlying data. | |
85aaf69f | 545 | let arc = Arc::new(Mutex::new(1)); |
1a4d82fc JJ |
546 | let arc2 = Arc::new(Mutex::new(arc)); |
547 | let (tx, rx) = channel(); | |
85aaf69f | 548 | let _t = thread::spawn(move|| { |
1a4d82fc JJ |
549 | let lock = arc2.lock().unwrap(); |
550 | let lock2 = lock.lock().unwrap(); | |
551 | assert_eq!(*lock2, 1); | |
552 | tx.send(()).unwrap(); | |
553 | }); | |
554 | rx.recv().unwrap(); | |
555 | } | |
556 | ||
557 | #[test] | |
558 | fn test_mutex_arc_access_in_unwind() { | |
85aaf69f | 559 | let arc = Arc::new(Mutex::new(1)); |
1a4d82fc | 560 | let arc2 = arc.clone(); |
85aaf69f | 561 | let _ = thread::spawn(move|| -> () { |
1a4d82fc | 562 | struct Unwinder { |
c34b1796 | 563 | i: Arc<Mutex<i32>>, |
1a4d82fc JJ |
564 | } |
565 | impl Drop for Unwinder { | |
566 | fn drop(&mut self) { | |
567 | *self.i.lock().unwrap() += 1; | |
568 | } | |
569 | } | |
570 | let _u = Unwinder { i: arc2 }; | |
571 | panic!(); | |
572 | }).join(); | |
573 | let lock = arc.lock().unwrap(); | |
574 | assert_eq!(*lock, 2); | |
575 | } | |
d9579d0f | 576 | |
b039eaaf SL |
577 | #[test] |
578 | fn test_mutex_unsized() { | |
579 | let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); | |
580 | { | |
581 | let b = &mut *mutex.lock().unwrap(); | |
582 | b[0] = 4; | |
583 | b[2] = 5; | |
584 | } | |
585 | let comp: &[i32] = &[4, 2, 5]; | |
586 | assert_eq!(&*mutex.lock().unwrap(), comp); | |
587 | } | |
1a4d82fc | 588 | } |