use crate::core::detector::GLOBAL_DETECTOR;
use crate::core::detector::deadlock_handling;
use crate::core::logger;
use crate::core::types::DeadlockInfo;
use crate::core::{Detector, Events, WaitIntent, WaitMode, get_current_thread_id};
use crate::{LockId, ThreadId};
#[cfg(feature = "stress-test")]
use std::thread;
impl Detector {
pub fn create_mutex(&mut self, lock_id: LockId, creator_id: Option<ThreadId>) {
let creator = creator_id.unwrap_or_else(get_current_thread_id);
logger::log_lock_event(lock_id, Some(creator), Events::MutexSpawn);
}
pub fn destroy_mutex(&mut self, lock_id: LockId) {
self.mutex_owners.remove(&lock_id);
let waiters: Vec<_> = self
.thread_waits_for
.iter()
.filter_map(|(&thread_id, intent)| (intent.lock_id == lock_id).then_some(thread_id))
.collect();
for thread_id in waiters {
self.clear_wait_intent(thread_id);
}
logger::log_lock_event(lock_id, None, Events::MutexExit);
for holds in self.thread_holds.values_mut() {
holds.remove(&lock_id);
}
#[cfg(feature = "lock-order-graph")]
if let Some(graph) = &mut self.lock_order_graph {
graph.remove_lock(lock_id);
}
self.lock_waiters.remove(&lock_id);
}
pub fn acquire_slow(
&mut self,
thread_id: ThreadId,
lock_id: LockId,
potential_owner: Option<ThreadId>,
) -> Option<Vec<ThreadId>> {
logger::log_interaction_event(thread_id, lock_id, Events::MutexAttempt);
let effective_owner = potential_owner.or_else(|| self.mutex_owners.get(&lock_id).copied());
if let Some(owner) = effective_owner {
self.mutex_owners.insert(lock_id, owner);
}
if let Some(cycle) =
self.register_wait(thread_id, WaitIntent::new(lock_id, WaitMode::Mutex))
{
let filtered_cycle = self.filter_cycle_by_common_locks(&cycle);
if !filtered_cycle.is_empty() {
return Some(cycle);
}
}
None
}
pub fn complete_acquire(
&mut self,
thread_id: ThreadId,
lock_id: LockId,
) -> Option<DeadlockInfo> {
self.mutex_owners.insert(lock_id, thread_id);
#[allow(unused_mut)]
let mut deadlock_info = None;
#[cfg(feature = "lock-order-graph")]
if self.lock_order_graph.is_some()
&& self.thread_holds.get(&thread_id).map_or(0, |h| h.len()) >= 1
&& let Some(lock_cycle) = self.check_lock_order_violation(thread_id, lock_id)
{
deadlock_info =
Some(self.extract_lock_order_violation_info(thread_id, lock_id, lock_cycle));
}
self.thread_holds
.entry(thread_id)
.or_default()
.insert(lock_id);
self.clear_wait_intent(thread_id);
if let Some(cycle) = self.refresh_waiters_for_lock(lock_id)
&& let Some(info) = self.validated_deadlock_info(cycle)
{
deadlock_info = Some(info);
}
logger::log_interaction_event(thread_id, lock_id, Events::MutexAcquired);
deadlock_info
}
pub fn release_mutex(&mut self, thread_id: ThreadId, lock_id: LockId) {
logger::log_interaction_event(thread_id, lock_id, Events::MutexReleased);
if self.mutex_owners.get(&lock_id) == Some(&thread_id) {
self.mutex_owners.remove(&lock_id);
}
if let Some(holds) = self.thread_holds.get_mut(&thread_id) {
holds.remove(&lock_id);
if holds.is_empty() {
self.thread_holds.remove(&thread_id);
}
}
self.refresh_waiters_for_lock(lock_id);
#[cfg(feature = "stress-test")]
self.stress_on_lock_release(thread_id, lock_id);
}
}
pub fn create_mutex(lock_id: LockId, creator_id: Option<ThreadId>) {
let mut detector = GLOBAL_DETECTOR.lock();
detector.create_mutex(lock_id, creator_id);
}
pub fn destroy_mutex(lock_id: LockId) {
let mut detector = GLOBAL_DETECTOR.lock();
detector.destroy_mutex(lock_id);
}
pub fn release_mutex(thread_id: ThreadId, lock_id: LockId) {
let mut detector = GLOBAL_DETECTOR.lock();
detector.release_mutex(thread_id, lock_id);
}
pub fn complete_acquire(thread_id: ThreadId, lock_id: LockId) {
let deadlock_info = {
let mut detector = GLOBAL_DETECTOR.lock();
detector.complete_acquire(thread_id, lock_id)
};
if let Some(info) = deadlock_info {
deadlock_handling::process_deadlock(info);
}
}
#[cfg(all(test, not(feature = "lock-order-graph")))]
pub(crate) fn owner_for_test(lock_id: LockId) -> Option<ThreadId> {
GLOBAL_DETECTOR.lock().mutex_owners.get(&lock_id).copied()
}
pub fn acquire_slow_with_recheck<T, F, H>(
thread_id: ThreadId,
lock_id: LockId,
try_acquire: F,
owner_hint: H,
) -> (Option<T>, Option<DeadlockInfo>)
where
F: FnOnce() -> Option<T>,
H: FnOnce() -> Option<ThreadId>,
{
#[cfg(feature = "stress-test")]
{
let delay = {
let detector = GLOBAL_DETECTOR.lock();
detector.calculate_stress_delay(thread_id, lock_id)
};
if let Some(duration) = delay {
thread::sleep(duration);
}
}
let mut detector = GLOBAL_DETECTOR.lock();
if let Some(acquired) = try_acquire() {
let info = detector.complete_acquire(thread_id, lock_id);
return (Some(acquired), info);
}
let cycle = detector.acquire_slow(thread_id, lock_id, owner_hint());
let info = cycle.and_then(|cycle| detector.validated_deadlock_info(cycle));
(None, info)
}