use once_spin::*; use std::{ mem::forget, sync::{ atomic::{AtomicUsize, Ordering}, mpsc::channel, Arc, }, thread, }; #[derive(Eq, PartialEq, Debug)] struct NonCopy(i32); #[test] fn smoke() { let m = Mutex::new(()); drop(m.lock()); drop(m.lock()); } #[test] fn lots_and_lots() { static M: Mutex<()> = Mutex::new(()); static mut CNT: u32 = 0; const J: u32 = 1000; const K: u32 = 3; fn inc() { for _ in 0..J { unsafe { let _g = M.lock(); CNT += 1; } } } let (tx, rx) = channel(); for _ in 0..K { let tx2 = tx.clone(); thread::spawn(move || { inc(); tx2.send(()).unwrap(); }); let tx2 = tx.clone(); thread::spawn(move || { inc(); tx2.send(()).unwrap(); }); } drop(tx); for _ in 0..2 * K { rx.recv().unwrap(); } assert_eq!(unsafe { CNT }, J * K * 2); } #[test] fn try_lock() { let mutex = Mutex::new(42); let a = mutex.try_lock(); assert_eq!(a.as_ref().map(|r| **r), Some(42)); let b = mutex.try_lock(); assert!(b.is_none()); drop(a); let c = mutex.try_lock(); assert_eq!(c.as_ref().map(|r| **r), Some(42)); } #[test] fn test_into_inner() { let m = Mutex::new(NonCopy(10)); assert_eq!(m.into_inner(), NonCopy(10)); } #[test] fn test_into_inner_drop() { struct Foo(Arc); 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(); assert_eq!(num_drops.load(Ordering::SeqCst), 0); } assert_eq!(num_drops.load(Ordering::SeqCst), 1); } #[test] fn test_mutex_arc_nested() { let arc = Arc::new(Mutex::new(1)); let arc2 = Arc::new(Mutex::new(arc)); let (tx, rx) = channel(); let _t = thread::spawn(move || { let lock = arc2.lock(); let lock2 = lock.lock(); assert_eq!(*lock2, 1); tx.send(()).unwrap(); }); rx.recv().unwrap(); } #[test] fn test_mutex_arc_access_in_unwind() { let arc = Arc::new(Mutex::new(1)); let arc2 = arc.clone(); let _ = thread::spawn(move || -> () { struct Unwinder { i: Arc>, } impl Drop for Unwinder { fn drop(&mut self) { *self.i.lock() += 1; } } let _u = Unwinder { i: arc2 }; panic!(); }) .join(); let lock = arc.lock(); assert_eq!(*lock, 2); } #[test] fn test_mutex_unsized() { let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); { let b = &mut *mutex.lock(); b[0] = 4; b[2] = 5; } let comp: &[i32] = &[4, 2, 5]; assert_eq!(&*mutex.lock(), comp); } #[test] fn test_mutex_force_lock() { let lock = Mutex::new(()); forget(lock.lock()); unsafe { lock.force_unlock(); } assert!(lock.try_lock().is_some()); }