summaryrefslogtreecommitdiff
path: root/tests/evil_try_mutex.rs
blob: 5c31a9152a930826d8440b5ab6507b7a2f089514 (plain)
use std::sync::Arc;

use happylock::{
	collection::{BoxedLockCollection, RetryingLockCollection},
	mutex::Mutex,
	ThreadKey,
};
use lock_api::{GuardNoSend, RawMutex};

struct EvilMutex {
	inner: parking_lot::RawMutex,
}

unsafe impl RawMutex for EvilMutex {
	#[allow(clippy::declare_interior_mutable_const)]
	const INIT: Self = Self {
		inner: parking_lot::RawMutex::INIT,
	};

	type GuardMarker = GuardNoSend;

	fn lock(&self) {
		self.inner.lock()
	}

	fn try_lock(&self) -> bool {
		panic!("mwahahahaha");
	}

	unsafe fn unlock(&self) {
		self.inner.unlock()
	}
}

#[test]
fn boxed_mutexes() {
	let mut key = ThreadKey::get().unwrap();
	let good_mutex: Arc<Mutex<i32, parking_lot::RawMutex>> = Arc::new(Mutex::new(5));
	let evil_mutex: Arc<Mutex<i32, EvilMutex>> = Arc::new(Mutex::new(7));
	let useless_mutex: Arc<Mutex<i32, parking_lot::RawMutex>> = Arc::new(Mutex::new(10));
	let c_good = Arc::clone(&good_mutex);
	let c_evil = Arc::clone(&evil_mutex);
	let c_useless = Arc::clone(&useless_mutex);

	let r = std::thread::spawn(move || {
		let key = ThreadKey::get().unwrap();
		let collection = BoxedLockCollection::try_new((&*c_good, &*c_evil, &*c_useless)).unwrap();
		let g = collection.try_lock(key);
		println!("{}", g.unwrap().1);
	})
	.join();

	assert!(r.is_err());
	assert!(good_mutex.scoped_try_lock(&mut key, |_| {}).is_ok());
	assert!(evil_mutex.scoped_try_lock(&mut key, |_| {}).is_err());
	assert!(useless_mutex.scoped_try_lock(&mut key, |_| {}).is_ok());
}

#[test]
fn retrying_mutexes() {
	let mut key = ThreadKey::get().unwrap();
	let good_mutex: Arc<Mutex<i32, parking_lot::RawMutex>> = Arc::new(Mutex::new(5));
	let evil_mutex: Arc<Mutex<i32, EvilMutex>> = Arc::new(Mutex::new(7));
	let useless_mutex: Arc<Mutex<i32, parking_lot::RawMutex>> = Arc::new(Mutex::new(10));
	let c_good = Arc::clone(&good_mutex);
	let c_evil = Arc::clone(&evil_mutex);
	let c_useless = Arc::clone(&useless_mutex);

	let r = std::thread::spawn(move || {
		let key = ThreadKey::get().unwrap();
		let collection =
			RetryingLockCollection::try_new((&*c_good, &*c_evil, &*c_useless)).unwrap();
		let _ = collection.try_lock(key);
	})
	.join();

	assert!(r.is_err());
	assert!(good_mutex.scoped_try_lock(&mut key, |_| {}).is_ok());
	assert!(evil_mutex.scoped_try_lock(&mut key, |_| {}).is_err());
	assert!(useless_mutex.scoped_try_lock(&mut key, |_| {}).is_ok());
}