Add new reset_dependencies API

This commit is contained in:
2025-03-01 13:25:20 +01:00
parent ebdb6a18fe
commit d1a6b93ea8
4 changed files with 93 additions and 0 deletions

View File

@@ -99,6 +99,7 @@ pub mod lockapi;
pub mod parkinglot; pub mod parkinglot;
mod reporting; mod reporting;
pub mod stdsync; pub mod stdsync;
pub mod util;
thread_local! { thread_local! {
/// Stack to track which locks are held /// Stack to track which locks are held

View File

@@ -23,7 +23,9 @@ use lock_api::RawRwLockUpgradeDowngrade;
use lock_api::RawRwLockUpgradeFair; use lock_api::RawRwLockUpgradeFair;
use lock_api::RawRwLockUpgradeTimed; use lock_api::RawRwLockUpgradeTimed;
use crate::util::PrivateTraced;
use crate::LazyMutexId; use crate::LazyMutexId;
use crate::MutexId;
/// Tracing wrapper for all [`lock_api`] traits. /// Tracing wrapper for all [`lock_api`] traits.
/// ///
@@ -86,6 +88,12 @@ impl<T> TracingWrapper<T> {
} }
} }
impl<T> PrivateTraced for TracingWrapper<T> {
fn get_id(&self) -> &MutexId {
&self.id
}
}
unsafe impl<T> RawMutex for TracingWrapper<T> unsafe impl<T> RawMutex for TracingWrapper<T>
where where
T: RawMutex, T: RawMutex,

View File

@@ -10,6 +10,7 @@ use std::sync::TryLockResult;
use std::sync::WaitTimeoutResult; use std::sync::WaitTimeoutResult;
use std::time::Duration; use std::time::Duration;
use crate::util::PrivateTraced;
use crate::BorrowedMutex; use crate::BorrowedMutex;
use crate::LazyMutexId; use crate::LazyMutexId;
@@ -127,6 +128,12 @@ impl<T> Mutex<T> {
} }
} }
impl<T> PrivateTraced for Mutex<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> From<T> for Mutex<T> { impl<T> From<T> for Mutex<T> {
fn from(t: T) -> Self { fn from(t: T) -> Self {
Self::new(t) Self::new(t)
@@ -375,6 +382,12 @@ impl<T> RwLock<T> {
} }
} }
impl<T> PrivateTraced for RwLock<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> From<T> for RwLock<T> { impl<T> From<T> for RwLock<T> {
fn from(t: T) -> Self { fn from(t: T) -> Self {
Self::new(t) Self::new(t)
@@ -455,6 +468,12 @@ impl Once {
} }
} }
impl PrivateTraced for Once {
fn get_id(&self) -> &crate::MutexId {
&self.mutex_id
}
}
/// Wrapper for [`std::sync::OnceLock`] /// Wrapper for [`std::sync::OnceLock`]
/// ///
/// The exact locking behaviour of [`std::sync::OnceLock`] is currently undefined, but may /// The exact locking behaviour of [`std::sync::OnceLock`] is currently undefined, but may
@@ -553,6 +572,12 @@ impl<T> OnceLock<T> {
} }
} }
impl<T> PrivateTraced for OnceLock<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> Default for OnceLock<T> { impl<T> Default for OnceLock<T> {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {

59
src/util.rs Normal file
View File

@@ -0,0 +1,59 @@
use crate::MutexId;
/// Reset the dependencies for the given entity.
///
/// # Performance
///
/// This function locks the dependency graph to remove the item from it. This is an `O(E)` operation
/// with `E` being the number of dependencies directly associated with this particular instance. As
/// such, it is not advisable to call this method from a hot loop.
///
/// # Safety
///
/// Use of this method invalidates the deadlock prevention guarantees that this library makes. As
/// such, it should only be used when it is absolutely certain this will not introduce deadlocks
/// later.
///
/// Other than deadlocks, no undefined behaviour can result from the use of this function.
///
/// # Example
///
/// ```
/// use tracing_mutex::stdsync::Mutex;
/// use tracing_mutex::util;
///
/// let first = Mutex::new(());
/// let second = Mutex::new(());
///
/// {
/// let _first_lock = first.lock().unwrap();
/// second.lock().unwrap();
/// }
///
/// // Reset the dependencies for the first mutex
/// unsafe { util::reset_dependencies(&first) };
///
/// // Now we can unlock the mutexes in the opposite order without a panic.
/// let _second_lock = second.lock().unwrap();
/// first.lock().unwrap();
/// ```
pub unsafe fn reset_dependencies<T: Traced>(traced: &T) {
crate::get_dependency_graph().remove_node(traced.get_id().value());
}
/// Types that participate in dependency tracking
///
/// This trait is a public marker trait and is automatically implemented fore all types that
/// implement the internal dependency tracking features.
#[allow(private_bounds)]
pub trait Traced: PrivateTraced {}
impl<T: PrivateTraced> Traced for T {}
/// Private implementation of the traced marker.
///
/// This trait is private (and seals the outer trait) to avoid exposing the MutexId type.
pub(crate) trait PrivateTraced {
/// Get the mutex id associated with this traced item.
fn get_id(&self) -> &MutexId;
}