use crate::metrics_util::warn_if_takes_too_long; use std::sync::{Arc, Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::time::Duration; /// Attempts to lock the given mutex. /// /// Returns the guard even if mutex is poisoned. /// /// # Panics /// /// Panics in debug builds if already locked (blocks in release builds). pub fn non_blocking_lock<'a, T>( mutex: &'a Mutex, description: &'static str, ) -> MutexGuard<'a, T> { // TODO-high-performance This panics when pressing play. Check it out! // #[cfg(debug_assertions)] // match mutex.try_lock() { // Ok(g) => g, // Err(std::sync::TryLockError::Poisoned(e)) => e.into_inner(), // Err(std::sync::TryLockError::WouldBlock) => { // panic!("locking mutex would block: {}", description) // } // } // #[cfg(not(debug_assertions))] blocking_lock(mutex, description) } /// Locks the given mutex. /// /// Returns the guard even if mutex is poisoned. pub fn blocking_lock_arc<'a, T>( mutex: &'a Arc>, description: &'static str, ) -> MutexGuard<'a, T> { blocking_lock(&**mutex, description) } /// Locks the given mutex. /// /// Returns the guard even if mutex is poisoned. pub fn blocking_lock<'a, T>(mutex: &'a Mutex, description: &'static str) -> MutexGuard<'a, T> { warn_if_takes_too_long(description, MAX_MUTEX_LOCK_DURATION, || { match mutex.lock() { Ok(g) => g, Err(e) => e.into_inner(), } }) } /// Locks the given rw lock. /// /// Returns the guard even if mutex is poisoned. pub fn blocking_read_lock<'a, T>( rw_lock: &'a RwLock, description: &'static str, ) -> RwLockReadGuard<'a, T> { warn_if_takes_too_long(description, MAX_MUTEX_LOCK_DURATION, || { match rw_lock.read() { Ok(g) => g, Err(e) => e.into_inner(), } }) } /// Returns `None` if access would block. pub fn non_blocking_try_read_lock(rw_lock: &RwLock) -> Option> { match rw_lock.try_read() { Ok(g) => Some(g), Err(std::sync::TryLockError::Poisoned(e)) => Some(e.into_inner()), Err(std::sync::TryLockError::WouldBlock) => None, } } /// Locks the given rw lock. /// /// Returns the guard even if mutex is poisoned. pub fn blocking_write_lock<'a, T>( rw_lock: &'a RwLock, description: &'static str, ) -> RwLockWriteGuard<'a, T> { warn_if_takes_too_long(description, MAX_MUTEX_LOCK_DURATION, || { match rw_lock.write() { Ok(g) => g, Err(e) => e.into_inner(), } }) } const MAX_MUTEX_LOCK_DURATION: Duration = Duration::from_millis(30);