diff --git a/src/lib.rs b/src/lib.rs index 4c428e9..3bb51ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,6 +99,7 @@ pub mod lockapi; pub mod parkinglot; mod reporting; pub mod stdsync; +pub mod util; thread_local! { /// Stack to track which locks are held diff --git a/src/lockapi.rs b/src/lockapi.rs index 513dc60..5565d53 100644 --- a/src/lockapi.rs +++ b/src/lockapi.rs @@ -23,7 +23,9 @@ use lock_api::RawRwLockUpgradeDowngrade; use lock_api::RawRwLockUpgradeFair; use lock_api::RawRwLockUpgradeTimed; +use crate::util::PrivateTraced; use crate::LazyMutexId; +use crate::MutexId; /// Tracing wrapper for all [`lock_api`] traits. /// @@ -86,6 +88,12 @@ impl TracingWrapper { } } +impl PrivateTraced for TracingWrapper { + fn get_id(&self) -> &MutexId { + &self.id + } +} + unsafe impl RawMutex for TracingWrapper where T: RawMutex, diff --git a/src/stdsync/tracing.rs b/src/stdsync/tracing.rs index afc6998..a47d493 100644 --- a/src/stdsync/tracing.rs +++ b/src/stdsync/tracing.rs @@ -10,6 +10,7 @@ use std::sync::TryLockResult; use std::sync::WaitTimeoutResult; use std::time::Duration; +use crate::util::PrivateTraced; use crate::BorrowedMutex; use crate::LazyMutexId; @@ -127,6 +128,12 @@ impl Mutex { } } +impl PrivateTraced for Mutex { + fn get_id(&self) -> &crate::MutexId { + &self.id + } +} + impl From for Mutex { fn from(t: T) -> Self { Self::new(t) @@ -375,6 +382,12 @@ impl RwLock { } } +impl PrivateTraced for RwLock { + fn get_id(&self) -> &crate::MutexId { + &self.id + } +} + impl From for RwLock { fn from(t: T) -> Self { 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`] /// /// The exact locking behaviour of [`std::sync::OnceLock`] is currently undefined, but may @@ -553,6 +572,12 @@ impl OnceLock { } } +impl PrivateTraced for OnceLock { + fn get_id(&self) -> &crate::MutexId { + &self.id + } +} + impl Default for OnceLock { #[inline] fn default() -> Self { diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..6e12432 --- /dev/null +++ b/src/util.rs @@ -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(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 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; +}