]> git.proxmox.com Git - rustc.git/blame - src/libstd/sync/mutex.rs
New upstream version 1.33.0+dfsg1
[rustc.git] / src / libstd / sync / mutex.rs
CommitLineData
1a4d82fc 1use cell::UnsafeCell;
9346a6ac 2use fmt;
b039eaaf 3use mem;
1a4d82fc 4use ops::{Deref, DerefMut};
b039eaaf 5use ptr;
1a4d82fc 6use sys_common::mutex as sys;
9346a6ac 7use 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> {
1a4d82fc
JJ
146 // funny underscores due to how Deref/DerefMut currently work (they
147 // disregard field privacy).
5bcae85e 148 __lock: &'a Mutex<T>,
1a4d82fc 149 __poison: poison::Guard,
1a4d82fc
JJ
150}
151
92a42be0 152#[stable(feature = "rust1", since = "1.0.0")]
7cac9316
XL
153impl<'a, T: ?Sized> !Send for MutexGuard<'a, T> { }
154#[stable(feature = "mutexguard", since = "1.19.0")]
155unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> { }
85aaf69f 156
c34b1796 157impl<T> Mutex<T> {
1a4d82fc 158 /// Creates a new mutex in an unlocked state ready for use.
32a655c1
SL
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use std::sync::Mutex;
164 ///
165 /// let mutex = Mutex::new(0);
166 /// ```
85aaf69f 167 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 168 pub fn new(t: T) -> Mutex<T> {
3157f602 169 let mut m = Mutex {
5bcae85e
SL
170 inner: box sys::Mutex::new(),
171 poison: poison::Flag::new(),
1a4d82fc 172 data: UnsafeCell::new(t),
3157f602
XL
173 };
174 unsafe {
5bcae85e 175 m.inner.init();
1a4d82fc 176 }
3157f602 177 m
1a4d82fc 178 }
d9579d0f 179}
1a4d82fc 180
d9579d0f 181impl<T: ?Sized> Mutex<T> {
bd371182 182 /// Acquires a mutex, blocking the current thread until it is able to do so.
1a4d82fc 183 ///
bd371182 184 /// This function will block the local thread until it is available to acquire
cc61c64b 185 /// the mutex. Upon returning, the thread is the only thread with the lock
1a4d82fc
JJ
186 /// held. An RAII guard is returned to allow scoped unlock of the lock. When
187 /// the guard goes out of scope, the mutex will be unlocked.
188 ///
a7813a04
XL
189 /// The exact behavior on locking a mutex in the thread which already holds
190 /// the lock is left unspecified. However, this function will not return on
191 /// the second call (it might panic or deadlock, for example).
192 ///
7453a54e 193 /// # Errors
1a4d82fc
JJ
194 ///
195 /// If another user of this mutex panicked while holding the mutex, then
196 /// this call will return an error once the mutex is acquired.
a7813a04
XL
197 ///
198 /// # Panics
199 ///
200 /// This function might panic when called if the lock is already held by
201 /// the current thread.
32a655c1
SL
202 ///
203 /// # Examples
204 ///
205 /// ```
206 /// use std::sync::{Arc, Mutex};
207 /// use std::thread;
208 ///
209 /// let mutex = Arc::new(Mutex::new(0));
210 /// let c_mutex = mutex.clone();
211 ///
212 /// thread::spawn(move || {
213 /// *c_mutex.lock().unwrap() = 10;
214 /// }).join().expect("thread::spawn failed");
215 /// assert_eq!(*mutex.lock().unwrap(), 10);
216 /// ```
85aaf69f 217 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 218 pub fn lock(&self) -> LockResult<MutexGuard<T>> {
7453a54e 219 unsafe {
94b46f34 220 self.inner.raw_lock();
5bcae85e 221 MutexGuard::new(self)
7453a54e 222 }
1a4d82fc
JJ
223 }
224
225 /// Attempts to acquire this lock.
226 ///
ea8adc8c 227 /// If the lock could not be acquired at this time, then [`Err`] is returned.
1a4d82fc
JJ
228 /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
229 /// guard is dropped.
230 ///
231 /// This function does not block.
232 ///
7453a54e 233 /// # Errors
1a4d82fc
JJ
234 ///
235 /// If another user of this mutex panicked while holding the mutex, then
236 /// this call will return failure if the mutex would otherwise be
237 /// acquired.
32a655c1 238 ///
ea8adc8c
XL
239 /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
240 ///
32a655c1
SL
241 /// # Examples
242 ///
243 /// ```
244 /// use std::sync::{Arc, Mutex};
245 /// use std::thread;
246 ///
247 /// let mutex = Arc::new(Mutex::new(0));
248 /// let c_mutex = mutex.clone();
249 ///
250 /// thread::spawn(move || {
251 /// let mut lock = c_mutex.try_lock();
252 /// if let Ok(ref mut mutex) = lock {
253 /// **mutex = 10;
254 /// } else {
255 /// println!("try_lock failed");
256 /// }
257 /// }).join().expect("thread::spawn failed");
258 /// assert_eq!(*mutex.lock().unwrap(), 10);
259 /// ```
85aaf69f 260 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 261 pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
7453a54e 262 unsafe {
5bcae85e
SL
263 if self.inner.try_lock() {
264 Ok(MutexGuard::new(self)?)
7453a54e
SL
265 } else {
266 Err(TryLockError::WouldBlock)
267 }
1a4d82fc
JJ
268 }
269 }
85aaf69f 270
cc61c64b 271 /// Determines whether the mutex is poisoned.
85aaf69f 272 ///
cc61c64b 273 /// If another thread is active, the mutex can still become poisoned at any
32a655c1 274 /// time. You should not trust a `false` value for program correctness
85aaf69f 275 /// without additional synchronization.
32a655c1
SL
276 ///
277 /// # Examples
278 ///
279 /// ```
280 /// use std::sync::{Arc, Mutex};
281 /// use std::thread;
282 ///
283 /// let mutex = Arc::new(Mutex::new(0));
284 /// let c_mutex = mutex.clone();
285 ///
286 /// let _ = thread::spawn(move || {
287 /// let _lock = c_mutex.lock().unwrap();
288 /// panic!(); // the mutex gets poisoned
289 /// }).join();
290 /// assert_eq!(mutex.is_poisoned(), true);
291 /// ```
85aaf69f 292 #[inline]
62682a34 293 #[stable(feature = "sync_poison", since = "1.2.0")]
85aaf69f 294 pub fn is_poisoned(&self) -> bool {
5bcae85e 295 self.poison.get()
85aaf69f 296 }
b039eaaf
SL
297
298 /// Consumes this mutex, returning the underlying data.
299 ///
7453a54e 300 /// # Errors
b039eaaf
SL
301 ///
302 /// If another user of this mutex panicked while holding the mutex, then
303 /// this call will return an error instead.
32a655c1
SL
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use std::sync::Mutex;
309 ///
310 /// let mutex = Mutex::new(0);
311 /// assert_eq!(mutex.into_inner().unwrap(), 0);
312 /// ```
92a42be0 313 #[stable(feature = "mutex_into_inner", since = "1.6.0")]
b039eaaf
SL
314 pub fn into_inner(self) -> LockResult<T> where T: Sized {
315 // We know statically that there are no outstanding references to
cc61c64b 316 // `self` so there's no need to lock the inner mutex.
b039eaaf
SL
317 //
318 // To get the inner value, we'd like to call `data.into_inner()`,
319 // but because `Mutex` impl-s `Drop`, we can't move out of it, so
320 // we'll have to destructure it manually instead.
321 unsafe {
5bcae85e
SL
322 // Like `let Mutex { inner, poison, data } = self`.
323 let (inner, poison, data) = {
324 let Mutex { ref inner, ref poison, ref data } = self;
325 (ptr::read(inner), ptr::read(poison), ptr::read(data))
b039eaaf
SL
326 };
327 mem::forget(self);
5bcae85e
SL
328 inner.destroy(); // Keep in sync with the `Drop` impl.
329 drop(inner);
b039eaaf 330
5bcae85e 331 poison::map_result(poison.borrow(), |_| data.into_inner())
b039eaaf
SL
332 }
333 }
334
335 /// Returns a mutable reference to the underlying data.
336 ///
337 /// Since this call borrows the `Mutex` mutably, no actual locking needs to
338 /// take place---the mutable borrow statically guarantees no locks exist.
339 ///
7453a54e 340 /// # Errors
b039eaaf
SL
341 ///
342 /// If another user of this mutex panicked while holding the mutex, then
343 /// this call will return an error instead.
32a655c1
SL
344 ///
345 /// # Examples
346 ///
347 /// ```
348 /// use std::sync::Mutex;
349 ///
350 /// let mut mutex = Mutex::new(0);
351 /// *mutex.get_mut().unwrap() = 10;
352 /// assert_eq!(*mutex.lock().unwrap(), 10);
353 /// ```
92a42be0 354 #[stable(feature = "mutex_get_mut", since = "1.6.0")]
b039eaaf
SL
355 pub fn get_mut(&mut self) -> LockResult<&mut T> {
356 // We know statically that there are no other references to `self`, so
cc61c64b 357 // there's no need to lock the inner mutex.
b039eaaf 358 let data = unsafe { &mut *self.data.get() };
5bcae85e 359 poison::map_result(self.poison.borrow(), |_| data )
b039eaaf 360 }
1a4d82fc
JJ
361}
362
85aaf69f 363#[stable(feature = "rust1", since = "1.0.0")]
32a655c1 364unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> {
1a4d82fc
JJ
365 fn drop(&mut self) {
366 // This is actually safe b/c we know that there is no further usage of
367 // this mutex (it's up to the user to arrange for a mutex to get
368 // dropped, that's not our job)
b039eaaf
SL
369 //
370 // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
5bcae85e 371 unsafe { self.inner.destroy() }
1a4d82fc
JJ
372 }
373}
374
2c00a5a8 375#[stable(feature = "mutex_from", since = "1.24.0")]
ff7c6d11
XL
376impl<T> From<T> for Mutex<T> {
377 /// Creates a new mutex in an unlocked state ready for use.
378 /// This is equivalent to [`Mutex::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> {
c34b1796
AL
394 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 {
403 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
404 }
405
406 f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
407 }
c34b1796
AL
408 }
409 }
410}
411
d9579d0f 412impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
5bcae85e 413 unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
1a4d82fc
JJ
414 poison::map_result(lock.poison.borrow(), |guard| {
415 MutexGuard {
416 __lock: lock,
1a4d82fc 417 __poison: guard,
1a4d82fc
JJ
418 }
419 })
420 }
421}
422
85aaf69f 423#[stable(feature = "rust1", since = "1.0.0")]
d9579d0f 424impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> {
1a4d82fc
JJ
425 type Target = T;
426
5bcae85e
SL
427 fn deref(&self) -> &T {
428 unsafe { &*self.__lock.data.get() }
429 }
1a4d82fc 430}
e9174d1e 431
85aaf69f 432#[stable(feature = "rust1", since = "1.0.0")]
d9579d0f 433impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
5bcae85e
SL
434 fn deref_mut(&mut self) -> &mut T {
435 unsafe { &mut *self.__lock.data.get() }
436 }
1a4d82fc
JJ
437}
438
85aaf69f 439#[stable(feature = "rust1", since = "1.0.0")]
d9579d0f 440impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
1a4d82fc
JJ
441 #[inline]
442 fn drop(&mut self) {
443 unsafe {
444 self.__lock.poison.done(&self.__poison);
94b46f34 445 self.__lock.inner.raw_unlock();
1a4d82fc
JJ
446 }
447 }
448}
449
8bb4bdeb 450#[stable(feature = "std_debug", since = "1.16.0")]
32a655c1
SL
451impl<'a, T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'a, T> {
452 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
453 f.debug_struct("MutexGuard")
454 .field("lock", &self.__lock)
455 .finish()
456 }
457}
458
041b39d2
XL
459#[stable(feature = "std_guard_impls", since = "1.20.0")]
460impl<'a, T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'a, T> {
461 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
462 (**self).fmt(f)
463 }
464}
465
d9579d0f 466pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
5bcae85e 467 &guard.__lock.inner
1a4d82fc
JJ
468}
469
d9579d0f 470pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
1a4d82fc
JJ
471 &guard.__lock.poison
472}
473
c30ab7b3 474#[cfg(all(test, not(target_os = "emscripten")))]
d9579d0f 475mod tests {
1a4d82fc 476 use sync::mpsc::channel;
5bcae85e 477 use sync::{Arc, Mutex, Condvar};
b039eaaf 478 use sync::atomic::{AtomicUsize, Ordering};
85aaf69f 479 use 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}