pub type SyncLockPool<K> = super::LockPoolImpl<K, std::sync::Mutex<()>>;
#[cfg(test)]
mod tests {
use super::SyncLockPool;
use crate::pool::tests::utils::{
launch_locking_owned_thread, launch_locking_thread, poison_lock, poison_lock_owned,
poison_try_lock, poison_try_lock_owned,
};
use crate::{LockPool, PoisonError, TryLockError, UnpoisonError};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
crate::instantiate_common_tests!(common, super::SyncLockPool<isize>);
fn assert_is_lock_poisoned_error<G>(expected_key: isize, error: &PoisonError<isize, G>) {
assert_eq!(expected_key, error.key);
}
fn assert_is_try_lock_poisoned_error<G>(expected_key: isize, error: &TryLockError<isize, G>) {
match error {
TryLockError::Poisoned(PoisonError {
key: actual_key, ..
}) => {
assert_eq!(expected_key, *actual_key);
}
_ => panic!("Wrong error type"),
}
}
#[test]
fn test_pool_mutex_poisoned_by_lock() {
let pool = Arc::new(SyncLockPool::new());
poison_lock(&pool, 3);
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
}
#[test]
fn test_pool_mutex_poisoned_by_lock_owned() {
let pool = Arc::new(SyncLockPool::new());
poison_lock_owned(&pool, 3);
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
}
#[test]
fn test_pool_mutex_poisoned_by_try_lock() {
let pool = Arc::new(SyncLockPool::new());
poison_try_lock(&pool, 3);
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
}
#[test]
fn test_pool_mutex_poisoned_by_try_lock_owned() {
let pool = Arc::new(SyncLockPool::new());
poison_try_lock_owned(&pool, 3);
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.lock_owned(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
{
let err = pool.try_lock_owned(3).unwrap_err();
assert_is_try_lock_poisoned_error(3, &err);
}
}
#[test]
fn test_poison_error_holds_lock() {
let pool = Arc::new(SyncLockPool::new());
poison_lock(&pool, 5);
let error = pool.lock(5).unwrap_err();
assert_is_lock_poisoned_error(5, &error);
let counter = Arc::new(AtomicU32::new(0));
let child = launch_locking_thread(&pool, 5, &counter, None);
thread::sleep(Duration::from_millis(100));
assert_eq!(0, counter.load(Ordering::SeqCst));
std::mem::drop(error);
child.join().unwrap_err();
assert_eq!(1, counter.load(Ordering::SeqCst));
assert_eq!(1, pool.num_locked_or_poisoned());
}
#[test]
fn test_poison_error_holds_lock_owned() {
let pool = Arc::new(SyncLockPool::new());
poison_lock_owned(&pool, 5);
let error = pool.lock_owned(5).unwrap_err();
assert_is_lock_poisoned_error(5, &error);
let counter = Arc::new(AtomicU32::new(0));
let child = launch_locking_owned_thread(&pool, 5, &counter, None);
thread::sleep(Duration::from_millis(100));
assert_eq!(0, counter.load(Ordering::SeqCst));
std::mem::drop(error);
child.join().unwrap_err();
assert_eq!(1, counter.load(Ordering::SeqCst));
assert_eq!(1, pool.num_locked_or_poisoned());
}
#[test]
fn test_poison_error_holds_try_lock() {
let pool = Arc::new(SyncLockPool::new());
poison_lock(&pool, 5);
let error = pool.lock(5).unwrap_err();
assert_is_lock_poisoned_error(5, &error);
let err = pool.try_lock(5).unwrap_err();
assert!(matches!(err, TryLockError::WouldBlock));
std::mem::drop(error);
let err = pool.try_lock(5).unwrap_err();
assert_is_try_lock_poisoned_error(5, &err);
assert_eq!(1, pool.num_locked_or_poisoned());
}
#[test]
fn test_poison_error_holds_try_lock_owned() {
let pool = Arc::new(SyncLockPool::new());
poison_lock_owned(&pool, 5);
let error = pool.lock_owned(5).unwrap_err();
assert_is_lock_poisoned_error(5, &error);
let err = pool.try_lock_owned(5).unwrap_err();
assert!(matches!(err, TryLockError::WouldBlock));
std::mem::drop(error);
let err = pool.try_lock(5).unwrap_err();
assert_is_try_lock_poisoned_error(5, &err);
assert_eq!(1, pool.num_locked_or_poisoned());
}
#[test]
fn test_unpoison() {
let pool = Arc::new(SyncLockPool::new());
poison_lock(&pool, 3);
{
let err = pool.lock(3).unwrap_err();
assert_is_lock_poisoned_error(3, &err);
}
pool.unpoison(3).unwrap();
{
let _g = pool.lock(3).unwrap();
}
{
let _g = pool.lock_owned(3).unwrap();
}
{
let _g = pool.try_lock(3).unwrap();
}
{
let _g = pool.try_lock_owned(3).unwrap();
}
}
#[test]
fn test_unpoison_not_poisoned() {
let pool = Arc::new(SyncLockPool::new());
let err = pool.unpoison(3).unwrap_err();
assert_eq!(UnpoisonError::NotPoisoned, err);
}
#[test]
fn test_unpoison_while_other_thread_waiting() {
let pool = Arc::new(SyncLockPool::new());
poison_lock(&pool, 3);
let _err_guard = pool.lock(3).unwrap_err();
let err = pool.unpoison(3).unwrap_err();
assert!(matches!(err, UnpoisonError::OtherThreadsBlockedOnMutex));
}
}