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