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