mutex.rs 22.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use prelude::v1::*;
12

F
Flavio Percoco 已提交
13
use cell::UnsafeCell;
14
use fmt;
N
Nick Cameron 已提交
15
use marker;
16
use mem;
17
use ops::{Deref, DerefMut};
18
use ptr;
A
Alex Crichton 已提交
19
use sys_common::mutex as sys;
20
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
21 22 23

/// A mutual exclusion primitive useful for protecting shared data
///
A
Alex Crichton 已提交
24 25 26 27 28 29 30 31 32
/// This mutex will block threads waiting for the lock to become available. The
/// mutex can also be statically initialized or created via a `new`
/// constructor. Each mutex has a type parameter which represents the data that
/// it is protecting. The data can only be accessed through the RAII guards
/// returned from `lock` and `try_lock`, which guarantees that the data is only
/// ever accessed when the mutex is locked.
///
/// # Poisoning
///
33 34
/// The mutexes in this module implement a strategy called "poisoning" where a
/// mutex is considered poisoned whenever a thread panics while holding the
35
/// lock. Once a mutex is poisoned, all other threads are unable to access the
36 37
/// data by default as it is likely tainted (some invariant is not being
/// upheld).
38
///
39 40 41 42 43 44
/// For a mutex, this means that the `lock` and `try_lock` methods return a
/// `Result` which indicates whether a mutex has been poisoned or not. Most
/// usage of a mutex will simply `unwrap()` these results, propagating panics
/// among threads to ensure that a possibly invalid invariant is not witnessed.
///
/// A poisoned mutex, however, does not prevent all access to the underlying
45
/// data. The `PoisonError` type has an `into_inner` method which will return
46 47 48 49
/// the guard that would have otherwise been returned on a successful lock. This
/// allows access to the data, despite the lock being poisoned.
///
/// # Examples
50
///
51
/// ```
A
Alex Crichton 已提交
52
/// use std::sync::{Arc, Mutex};
A
Aaron Turon 已提交
53
/// use std::thread;
54
/// use std::sync::mpsc::channel;
55
///
N
Nick Cameron 已提交
56
/// const N: usize = 10;
57
///
A
Alex Crichton 已提交
58 59 60
/// // Spawn a few threads to increment a shared variable (non-atomically), and
/// // let the main thread know once all increments are done.
/// //
61
/// // Here we're using an Arc to share memory among threads, and the data inside
A
Alex Crichton 已提交
62 63 64 65
/// // the Arc is protected with a mutex.
/// let data = Arc::new(Mutex::new(0));
///
/// let (tx, rx) = channel();
66
/// for _ in 0..10 {
A
Alex Crichton 已提交
67
///     let (data, tx) = (data.clone(), tx.clone());
A
Aaron Turon 已提交
68
///     thread::spawn(move || {
69
///         // The shared state can only be accessed once the lock is held.
A
Alex Crichton 已提交
70 71
///         // Our non-atomic increment is safe because we're the only thread
///         // which can access the shared state when the lock is held.
72 73
///         //
///         // We unwrap() the return value to assert that we are not expecting
74
///         // threads to ever fail while holding the lock.
75
///         let mut data = data.lock().unwrap();
A
Alex Crichton 已提交
76 77
///         *data += 1;
///         if *data == N {
78
///             tx.send(()).unwrap();
A
Alex Crichton 已提交
79 80
///         }
///         // the lock is unlocked here when `data` goes out of scope.
A
Aaron Turon 已提交
81
///     });
A
Alex Crichton 已提交
82 83
/// }
///
84
/// rx.recv().unwrap();
85
/// ```
86 87 88
///
/// To recover from a poisoned mutex:
///
89
/// ```
90
/// use std::sync::{Arc, Mutex};
A
Aaron Turon 已提交
91
/// use std::thread;
92
///
93
/// let lock = Arc::new(Mutex::new(0_u32));
94 95
/// let lock2 = lock.clone();
///
A
Aaron Turon 已提交
96
/// let _ = thread::spawn(move || -> () {
97 98
///     // This thread will acquire the mutex first, unwrapping the result of
///     // `lock` because the lock has not been poisoned.
99
///     let _guard = lock2.lock().unwrap();
100 101 102 103 104 105 106 107 108 109
///
///     // This panic while holding the lock (`_guard` is in scope) will poison
///     // the mutex.
///     panic!();
/// }).join();
///
/// // The lock is poisoned by this point, but the returned result can be
/// // pattern matched on to return the underlying guard on both branches.
/// let mut guard = match lock.lock() {
///     Ok(guard) => guard,
110
///     Err(poisoned) => poisoned.into_inner(),
111 112 113 114
/// };
///
/// *guard += 1;
/// ```
B
Brian Anderson 已提交
115
#[stable(feature = "rust1", since = "1.0.0")]
116
pub struct Mutex<T: ?Sized> {
A
Alex Crichton 已提交
117
    // Note that this static mutex is in a *box*, not inlined into the struct
A
Alex Crichton 已提交
118 119 120 121 122
    // itself. Once a native mutex has been used once, its address can never
    // change (it can't be moved). This mutex type can be safely moved at any
    // time, so to ensure that the native mutex is used correctly we box the
    // inner lock to give it a constant address.
    inner: Box<StaticMutex>,
123
    data: UnsafeCell<T>,
124 125
}

126 127
// these are the only places where `T: Send` matters; all other
// functionality works fine on a single thread.
128
#[stable(feature = "rust1", since = "1.0.0")]
129
unsafe impl<T: ?Sized + Send> Send for Mutex<T> { }
130
#[stable(feature = "rust1", since = "1.0.0")]
131
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
F
Flavio Percoco 已提交
132

133 134 135 136 137 138 139 140
/// The static mutex type is provided to allow for static allocation of mutexes.
///
/// Note that this is a separate type because using a Mutex correctly means that
/// it needs to have a destructor run. In Rust, statics are not allowed to have
/// destructors. As a result, a `StaticMutex` has one extra method when compared
/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
/// documentation can be found directly on the method.
///
S
Steve Klabnik 已提交
141
/// # Examples
142
///
143
/// ```
144 145
/// #![feature(static_mutex)]
///
A
Alex Crichton 已提交
146
/// use std::sync::{StaticMutex, MUTEX_INIT};
147
///
A
Alex Crichton 已提交
148
/// static LOCK: StaticMutex = MUTEX_INIT;
149
///
A
Alex Crichton 已提交
150
/// {
151
///     let _g = LOCK.lock().unwrap();
152 153 154 155
///     // do some productive work
/// }
/// // lock is unlocked here.
/// ```
156
#[unstable(feature = "static_mutex",
157 158
           reason = "may be merged with Mutex in the future",
           issue = "27717")]
159
pub struct StaticMutex {
A
Alex Crichton 已提交
160
    lock: sys::Mutex,
161
    poison: poison::Flag,
162 163 164 165
}

/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
A
Alex Crichton 已提交
166 167
///
/// The data protected by the mutex can be access through this guard via its
168
/// `Deref` and `DerefMut` implementations
169
#[must_use]
B
Brian Anderson 已提交
170
#[stable(feature = "rust1", since = "1.0.0")]
171
pub struct MutexGuard<'a, T: ?Sized + 'a> {
A
Alex Crichton 已提交
172 173
    // funny underscores due to how Deref/DerefMut currently work (they
    // disregard field privacy).
174
    __lock: &'a StaticMutex,
175
    __data: &'a mut T,
176
    __poison: poison::Guard,
177 178
}

179
#[stable(feature = "rust1", since = "1.0.0")]
180
impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {}
181

182 183
/// Static initialization of a mutex. This constant can be used to initialize
/// other mutex constants.
184
#[unstable(feature = "static_mutex",
185 186
           reason = "may be merged with Mutex in the future",
           issue = "27717")]
187
pub const MUTEX_INIT: StaticMutex = StaticMutex::new();
188

189
impl<T> Mutex<T> {
A
Alex Crichton 已提交
190
    /// Creates a new mutex in an unlocked state ready for use.
B
Brian Anderson 已提交
191
    #[stable(feature = "rust1", since = "1.0.0")]
A
Alex Crichton 已提交
192 193
    pub fn new(t: T) -> Mutex<T> {
        Mutex {
194
            inner: box StaticMutex::new(),
195
            data: UnsafeCell::new(t),
A
Alex Crichton 已提交
196 197
        }
    }
198
}
A
Alex Crichton 已提交
199

200
impl<T: ?Sized> Mutex<T> {
201
    /// Acquires a mutex, blocking the current thread until it is able to do so.
A
Alex Crichton 已提交
202
    ///
203 204
    /// This function will block the local thread until it is available to acquire
    /// the mutex. Upon returning, the thread is the only thread with the mutex
A
Alex Crichton 已提交
205 206 207
    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
    /// the guard goes out of scope, the mutex will be unlocked.
    ///
208 209 210 211
    /// The exact behavior on locking a mutex in the thread which already holds
    /// the lock is left unspecified, however, this function will not return on
    /// the second call, it might e.g. panic or deadlock.
    ///
212
    /// # Errors
A
Alex Crichton 已提交
213 214
    ///
    /// If another user of this mutex panicked while holding the mutex, then
215
    /// this call will return an error once the mutex is acquired.
216 217 218 219 220
    ///
    /// # Panics
    ///
    /// This function might panic when called if the lock is already held by
    /// the current thread.
B
Brian Anderson 已提交
221
    #[stable(feature = "rust1", since = "1.0.0")]
222
    pub fn lock(&self) -> LockResult<MutexGuard<T>> {
223 224 225 226
        unsafe {
            self.inner.lock.lock();
            MutexGuard::new(&*self.inner, &self.data)
        }
A
Alex Crichton 已提交
227 228 229 230
    }

    /// Attempts to acquire this lock.
    ///
231
    /// If the lock could not be acquired at this time, then `Err` is returned.
A
Alex Crichton 已提交
232 233 234 235 236
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    ///
237
    /// # Errors
A
Alex Crichton 已提交
238 239
    ///
    /// If another user of this mutex panicked while holding the mutex, then
240
    /// this call will return failure if the mutex would otherwise be
A
Alex Crichton 已提交
241
    /// acquired.
B
Brian Anderson 已提交
242
    #[stable(feature = "rust1", since = "1.0.0")]
243
    pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
244 245
        unsafe {
            if self.inner.lock.try_lock() {
J
Jorge Aparicio 已提交
246
                Ok(MutexGuard::new(&*self.inner, &self.data)?)
247 248 249
            } else {
                Err(TryLockError::WouldBlock)
            }
A
Alex Crichton 已提交
250
        }
251
    }
252

253
    /// Determines whether the lock is poisoned.
254 255 256 257 258
    ///
    /// If another thread is active, the lock can still become poisoned at any
    /// time.  You should not trust a `false` value for program correctness
    /// without additional synchronization.
    #[inline]
259
    #[stable(feature = "sync_poison", since = "1.2.0")]
260 261 262
    pub fn is_poisoned(&self) -> bool {
        self.inner.poison.get()
    }
263 264 265

    /// Consumes this mutex, returning the underlying data.
    ///
266
    /// # Errors
267 268 269
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error instead.
270
    #[stable(feature = "mutex_into_inner", since = "1.6.0")]
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    pub fn into_inner(self) -> LockResult<T> where T: Sized {
        // We know statically that there are no outstanding references to
        // `self` so there's no need to lock the inner StaticMutex.
        //
        // To get the inner value, we'd like to call `data.into_inner()`,
        // but because `Mutex` impl-s `Drop`, we can't move out of it, so
        // we'll have to destructure it manually instead.
        unsafe {
            // Like `let Mutex { inner, data } = self`.
            let (inner, data) = {
                let Mutex { ref inner, ref data } = self;
                (ptr::read(inner), ptr::read(data))
            };
            mem::forget(self);
            inner.lock.destroy();  // Keep in sync with the `Drop` impl.

            poison::map_result(inner.poison.borrow(), |_| data.into_inner())
        }
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    ///
296
    /// # Errors
297 298 299
    ///
    /// If another user of this mutex panicked while holding the mutex, then
    /// this call will return an error instead.
300
    #[stable(feature = "mutex_get_mut", since = "1.6.0")]
301 302 303 304 305 306
    pub fn get_mut(&mut self) -> LockResult<&mut T> {
        // We know statically that there are no other references to `self`, so
        // there's no need to lock the inner StaticMutex.
        let data = unsafe { &mut *self.data.get() };
        poison::map_result(self.inner.poison.borrow(), |_| data )
    }
A
Alex Crichton 已提交
307
}
308

B
Brian Anderson 已提交
309
#[stable(feature = "rust1", since = "1.0.0")]
310
impl<T: ?Sized> Drop for Mutex<T> {
311
    #[unsafe_destructor_blind_to_params]
A
Alex Crichton 已提交
312 313 314 315
    fn drop(&mut self) {
        // This is actually safe b/c we know that there is no further usage of
        // this mutex (it's up to the user to arrange for a mutex to get
        // dropped, that's not our job)
316 317
        //
        // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
A
Alex Crichton 已提交
318 319 320 321
        unsafe { self.inner.lock.destroy() }
    }
}

322 323 324 325 326 327 328
#[stable(feature = "mutex_default", since = "1.9.0")]
impl<T: ?Sized + Default> Default for Mutex<T> {
    fn default() -> Mutex<T> {
        Mutex::new(Default::default())
    }
}

329
#[stable(feature = "rust1", since = "1.0.0")]
330
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
331 332
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
333
            Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
334
            Err(TryLockError::Poisoned(err)) => {
335
                write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
336 337 338 339 340 341
            },
            Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
        }
    }
}

A
Alex Crichton 已提交
342 343
struct Dummy(UnsafeCell<()>);
unsafe impl Sync for Dummy {}
344
static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
345

346
#[unstable(feature = "static_mutex",
347 348
           reason = "may be merged with Mutex in the future",
           issue = "27717")]
A
Alex Crichton 已提交
349
impl StaticMutex {
350 351 352 353 354 355 356 357
    /// Creates a new mutex in an unlocked state ready for use.
    pub const fn new() -> StaticMutex {
        StaticMutex {
            lock: sys::Mutex::new(),
            poison: poison::Flag::new(),
        }
    }

358
    /// Acquires this lock, see `Mutex::lock`
359
    #[inline]
360
    pub fn lock(&'static self) -> LockResult<MutexGuard<()>> {
361 362 363 364
        unsafe {
            self.lock.lock();
            MutexGuard::new(self, &DUMMY.0)
        }
A
Alex Crichton 已提交
365 366 367
    }

    /// Attempts to grab this lock, see `Mutex::try_lock`
368
    #[inline]
369
    pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> {
370 371
        unsafe {
            if self.lock.try_lock() {
J
Jorge Aparicio 已提交
372
                Ok(MutexGuard::new(self, &DUMMY.0)?)
373 374 375
            } else {
                Err(TryLockError::WouldBlock)
            }
A
Alex Crichton 已提交
376
        }
377 378 379 380 381 382 383 384 385 386 387 388
    }

    /// Deallocates resources associated with this static mutex.
    ///
    /// This method is unsafe because it provides no guarantees that there are
    /// no active users of this mutex, and safety is not guaranteed if there are
    /// active users of this mutex.
    ///
    /// This method is required to ensure that there are no memory leaks on
    /// *all* platforms. It may be the case that some platforms do not leak
    /// memory if this method is not called, but this is not guaranteed to be
    /// true on all platforms.
A
Alex Crichton 已提交
389
    pub unsafe fn destroy(&'static self) {
390 391 392 393
        self.lock.destroy()
    }
}

394
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
395

396
    unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
397 398 399 400
           -> LockResult<MutexGuard<'mutex, T>> {
        poison::map_result(lock.poison.borrow(), |guard| {
            MutexGuard {
                __lock: lock,
401
                __data: &mut *data.get(),
402 403 404 405
                __poison: guard,
            }
        })
    }
A
Alex Crichton 已提交
406
}
407

B
Brian Anderson 已提交
408
#[stable(feature = "rust1", since = "1.0.0")]
409
impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> {
410 411
    type Target = T;

412
    fn deref(&self) -> &T {self.__data }
A
Alex Crichton 已提交
413
}
414

B
Brian Anderson 已提交
415
#[stable(feature = "rust1", since = "1.0.0")]
416
impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
417
    fn deref_mut(&mut self) -> &mut T { self.__data }
A
Alex Crichton 已提交
418 419
}

B
Brian Anderson 已提交
420
#[stable(feature = "rust1", since = "1.0.0")]
421
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
422
    #[inline]
423 424 425 426
    fn drop(&mut self) {
        unsafe {
            self.__lock.poison.done(&self.__poison);
            self.__lock.lock.unlock();
427 428 429 430
        }
    }
}

431
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
432
    &guard.__lock.lock
433 434
}

435
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
436
    &guard.__lock.poison
437 438 439
}

#[cfg(test)]
440
mod tests {
441
    use prelude::v1::*;
A
Alex Crichton 已提交
442

443
    use sync::mpsc::channel;
444
    use sync::{Arc, Mutex, StaticMutex, Condvar};
445
    use sync::atomic::{AtomicUsize, Ordering};
A
Aaron Turon 已提交
446
    use thread;
447

448
    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
449

450 451 452
    #[derive(Eq, PartialEq, Debug)]
    struct NonCopy(i32);

453
    unsafe impl<T: Send> Send for Packet<T> {}
454 455
    unsafe impl<T> Sync for Packet<T> {}

456 457
    #[test]
    fn smoke() {
A
Alex Crichton 已提交
458
        let m = Mutex::new(());
459 460
        drop(m.lock().unwrap());
        drop(m.lock().unwrap());
461 462 463 464
    }

    #[test]
    fn smoke_static() {
465
        static M: StaticMutex = StaticMutex::new();
466
        unsafe {
467 468
            drop(M.lock().unwrap());
            drop(M.lock().unwrap());
N
NODA, Kai 已提交
469
            M.destroy();
470 471 472 473 474
        }
    }

    #[test]
    fn lots_and_lots() {
475
        static M: StaticMutex = StaticMutex::new();
N
Nick Cameron 已提交
476
        static mut CNT: u32 = 0;
477 478
        const J: u32 = 1000;
        const K: u32 = 3;
479 480

        fn inc() {
481
            for _ in 0..J {
482
                unsafe {
483
                    let _g = M.lock().unwrap();
484 485 486 487 488
                    CNT += 1;
                }
            }
        }

489
        let (tx, rx) = channel();
490
        for _ in 0..K {
491
            let tx2 = tx.clone();
A
Aaron Turon 已提交
492
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
493
            let tx2 = tx.clone();
A
Aaron Turon 已提交
494
            thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
495 496
        }

497
        drop(tx);
498
        for _ in 0..2 * K {
499
            rx.recv().unwrap();
500
        }
N
NODA, Kai 已提交
501
        assert_eq!(unsafe {CNT}, J * K * 2);
502
        unsafe {
N
NODA, Kai 已提交
503
            M.destroy();
504 505 506 507
        }
    }

    #[test]
A
Alex Crichton 已提交
508 509
    fn try_lock() {
        let m = Mutex::new(());
510
        *m.try_lock().unwrap() = ();
511
    }
A
Alex Crichton 已提交
512

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
    #[test]
    fn test_into_inner() {
        let m = Mutex::new(NonCopy(10));
        assert_eq!(m.into_inner().unwrap(), NonCopy(10));
    }

    #[test]
    fn test_into_inner_drop() {
        struct Foo(Arc<AtomicUsize>);
        impl Drop for Foo {
            fn drop(&mut self) {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
        let num_drops = Arc::new(AtomicUsize::new(0));
        let m = Mutex::new(Foo(num_drops.clone()));
        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        {
            let _inner = m.into_inner().unwrap();
            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
        }
        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
    }

    #[test]
    fn test_into_inner_poison() {
        let m = Arc::new(Mutex::new(NonCopy(10)));
        let m2 = m.clone();
        let _ = thread::spawn(move || {
            let _lock = m2.lock().unwrap();
            panic!("test panic in inner thread to poison mutex");
        }).join();

        assert!(m.is_poisoned());
        match Arc::try_unwrap(m).unwrap().into_inner() {
            Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
            Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
        }
    }

    #[test]
    fn test_get_mut() {
        let mut m = Mutex::new(NonCopy(10));
        *m.get_mut().unwrap() = NonCopy(20);
        assert_eq!(m.into_inner().unwrap(), NonCopy(20));
    }

    #[test]
    fn test_get_mut_poison() {
        let m = Arc::new(Mutex::new(NonCopy(10)));
        let m2 = m.clone();
        let _ = thread::spawn(move || {
            let _lock = m2.lock().unwrap();
            panic!("test panic in inner thread to poison mutex");
        }).join();

        assert!(m.is_poisoned());
        match Arc::try_unwrap(m).unwrap().get_mut() {
            Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
            Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
        }
    }

A
Alex Crichton 已提交
576 577
    #[test]
    fn test_mutex_arc_condvar() {
578 579
        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
        let packet2 = Packet(packet.0.clone());
A
Alex Crichton 已提交
580
        let (tx, rx) = channel();
A
Aaron Turon 已提交
581
        let _t = thread::spawn(move|| {
A
Alex Crichton 已提交
582
            // wait until parent gets in
583
            rx.recv().unwrap();
584
            let &(ref lock, ref cvar) = &*packet2.0;
585
            let mut lock = lock.lock().unwrap();
A
Alex Crichton 已提交
586 587 588 589
            *lock = true;
            cvar.notify_one();
        });

590
        let &(ref lock, ref cvar) = &*packet.0;
591
        let mut lock = lock.lock().unwrap();
592
        tx.send(()).unwrap();
A
Alex Crichton 已提交
593 594
        assert!(!*lock);
        while !*lock {
595
            lock = cvar.wait(lock).unwrap();
A
Alex Crichton 已提交
596 597 598 599 600
        }
    }

    #[test]
    fn test_arc_condvar_poison() {
T
Tobias Bucher 已提交
601
        let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
602
        let packet2 = Packet(packet.0.clone());
A
Alex Crichton 已提交
603 604
        let (tx, rx) = channel();

A
Aaron Turon 已提交
605
        let _t = thread::spawn(move || -> () {
606
            rx.recv().unwrap();
607
            let &(ref lock, ref cvar) = &*packet2.0;
608
            let _g = lock.lock().unwrap();
A
Alex Crichton 已提交
609 610 611 612 613
            cvar.notify_one();
            // Parent should fail when it wakes up.
            panic!();
        });

614
        let &(ref lock, ref cvar) = &*packet.0;
615
        let mut lock = lock.lock().unwrap();
616
        tx.send(()).unwrap();
A
Alex Crichton 已提交
617
        while *lock == 1 {
618 619 620 621 622 623 624
            match cvar.wait(lock) {
                Ok(l) => {
                    lock = l;
                    assert_eq!(*lock, 1);
                }
                Err(..) => break,
            }
A
Alex Crichton 已提交
625 626 627 628 629
        }
    }

    #[test]
    fn test_mutex_arc_poison() {
T
Tobias Bucher 已提交
630
        let arc = Arc::new(Mutex::new(1));
631
        assert!(!arc.is_poisoned());
A
Alex Crichton 已提交
632
        let arc2 = arc.clone();
A
Aaron Turon 已提交
633
        let _ = thread::spawn(move|| {
634
            let lock = arc2.lock().unwrap();
A
Alex Crichton 已提交
635
            assert_eq!(*lock, 2);
A
Aaron Turon 已提交
636
        }).join();
637
        assert!(arc.lock().is_err());
638
        assert!(arc.is_poisoned());
A
Alex Crichton 已提交
639 640 641 642 643 644
    }

    #[test]
    fn test_mutex_arc_nested() {
        // Tests nested mutexes and access
        // to underlying data.
T
Tobias Bucher 已提交
645
        let arc = Arc::new(Mutex::new(1));
A
Alex Crichton 已提交
646 647
        let arc2 = Arc::new(Mutex::new(arc));
        let (tx, rx) = channel();
A
Aaron Turon 已提交
648
        let _t = thread::spawn(move|| {
649
            let lock = arc2.lock().unwrap();
650
            let lock2 = lock.lock().unwrap();
A
Alex Crichton 已提交
651
            assert_eq!(*lock2, 1);
652
            tx.send(()).unwrap();
A
Alex Crichton 已提交
653
        });
654
        rx.recv().unwrap();
A
Alex Crichton 已提交
655 656 657 658
    }

    #[test]
    fn test_mutex_arc_access_in_unwind() {
T
Tobias Bucher 已提交
659
        let arc = Arc::new(Mutex::new(1));
A
Alex Crichton 已提交
660
        let arc2 = arc.clone();
A
Aaron Turon 已提交
661
        let _ = thread::spawn(move|| -> () {
A
Alex Crichton 已提交
662
            struct Unwinder {
N
Nick Cameron 已提交
663
                i: Arc<Mutex<i32>>,
A
Alex Crichton 已提交
664 665 666
            }
            impl Drop for Unwinder {
                fn drop(&mut self) {
667
                    *self.i.lock().unwrap() += 1;
A
Alex Crichton 已提交
668 669 670 671
                }
            }
            let _u = Unwinder { i: arc2 };
            panic!();
A
Aaron Turon 已提交
672
        }).join();
673
        let lock = arc.lock().unwrap();
A
Alex Crichton 已提交
674 675
        assert_eq!(*lock, 2);
    }
676

677 678 679 680 681 682 683 684 685 686 687
    #[test]
    fn test_mutex_unsized() {
        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
        {
            let b = &mut *mutex.lock().unwrap();
            b[0] = 4;
            b[2] = 5;
        }
        let comp: &[i32] = &[4, 2, 5];
        assert_eq!(&*mutex.lock().unwrap(), comp);
    }
688
}