use std::sync::{Mutex, MutexGuard, PoisonError, TryLockError};
use std::time::Duration;
use super::tracker::*;
pub struct CheckedMutex<T> {
inner: Mutex<T>,
}
impl<T> CheckedMutex<T> {
pub fn new(t: T) -> CheckedMutex<T> {
CheckedMutex {
inner: Mutex::new(t),
}
}
}
type LockResult<'a, T> = Result<CheckedMutexGuard<'a, T>, PoisonError<MutexGuard<'a, T>>>;
type TryLockResult<'a, T> = Result<CheckedMutexGuard<'a, T>, TryLockError<MutexGuard<'a, T>>>;
impl<T> CheckedMutex<T> {
#[deprecated(note = "Please use cyfs_debug::lock! macro instead")]
pub fn lock(&self) -> LockResult<'_, T> {
self.lock_with_pos("")
}
#[deprecated(note = "Please use cyfs_debug::try_lock! macro instead")]
pub fn try_lock(&self) -> TryLockResult<'_, T> {
self.try_lock_with_pos("")
}
pub fn lock_with_pos(&self, pos: &str) -> LockResult<'_, T> {
#[cfg(feature = "trace")]
trace!("try enter mutex: {}", pos);
let _timer = TimeoutTracker::new(
TimeoutTrackerCategory::EnterLock,
pos,
Duration::from_secs(10),
);
self.inner.lock().map(|lock| {
#[cfg(feature = "trace")]
trace!("enter mutex: {}", pos);
CheckedMutexGuard::new(pos, lock)
})
}
pub fn try_lock_with_pos(&self, pos: &str) -> TryLockResult<'_, T> {
#[cfg(feature = "trace")]
trace!("try enter mutex: {}", pos);
match self.inner.try_lock() {
Ok(lock) => {
#[cfg(feature = "trace")]
trace!("enter mutex: {}", pos);
let ret = CheckedMutexGuard::new(pos, lock);
Ok(ret)
}
Err(e) => Err(e),
}
}
pub fn is_poisoned(&self) -> bool {
self.inner.is_poisoned()
}
pub fn into_inner(self) -> std::sync::LockResult<T>
where
T: Sized,
{
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> std::sync::LockResult<&mut T> {
self.inner.get_mut()
}
}
use std::fmt;
use std::ops::{Deref, DerefMut};
pub struct CheckedMutexGuard<'a, T: ?Sized + 'a> {
inner: MutexGuard<'a, T>,
timer: TimeoutTracker,
}
impl<'a, T: ?Sized> CheckedMutexGuard<'a, T> {
fn new(name: &str, lock: MutexGuard<'a, T>) -> Self {
let timer =
TimeoutTracker::new(TimeoutTrackerCategory::Lock, name, Duration::from_secs(10));
Self { inner: lock, timer }
}
}
impl<T: ?Sized> Deref for CheckedMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&*self.inner
}
}
impl<T: ?Sized> DerefMut for CheckedMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut *self.inner
}
}
impl<T: ?Sized> Drop for CheckedMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for CheckedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for CheckedMutexGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[allow(dead_code)]
#[macro_export]
macro_rules! lock {
($m:expr) => {
$m.lock_with_pos(&format!("{}:{}", file!(), line!()))
};
}
#[allow(dead_code)]
#[macro_export]
macro_rules! try_lock {
($m:expr) => {
$m.try_lock_with_pos(&format!("{}:{}", file!(), line!()))
};
}