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, 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);
for attempts in self.thread_waits_for.values_mut() {
if *attempts == lock_id {
*attempts = 0;
}
}
self.thread_waits_for.retain(|_, &mut l| l != 0);
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 = self.mutex_owners.get(&lock_id).copied().or_else(|| {
if let Some(owner) = potential_owner {
return Some(owner);
}
None
});
if let Some(owner) = effective_owner {
self.thread_waits_for.insert(thread_id, lock_id);
self.lock_waiters
.entry(lock_id)
.or_default()
.insert(thread_id);
if let Some(cycle) = self.wait_for_graph.add_edge(thread_id, owner) {
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);
if let Some(waiters) = self.lock_waiters.get_mut(&lock_id) {
waiters.remove(&thread_id);
if waiters.is_empty() {
self.lock_waiters.remove(&lock_id);
}
}
self.thread_waits_for.remove(&thread_id);
self.wait_for_graph.clear_wait_edges(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);
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);
}
}
if let Some(waiters) = self.lock_waiters.get(&lock_id) {
for &waiter in waiters {
self.wait_for_graph.remove_edge(waiter, thread_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);
}
}
pub fn acquire_slow(
thread_id: ThreadId,
lock_id: LockId,
potential_owner: Option<ThreadId>,
) -> Option<DeadlockInfo> {
#[cfg(feature = "stress-test")]
let delay = {
let detector = GLOBAL_DETECTOR.lock();
detector.calculate_stress_delay(thread_id, lock_id)
};
#[cfg(feature = "stress-test")]
if let Some(duration) = delay {
thread::sleep(duration);
}
{
let mut detector = GLOBAL_DETECTOR.lock();
let cycle = detector.acquire_slow(thread_id, lock_id, potential_owner);
cycle.map(|cycle| detector.extract_deadlock_info(cycle))
}
}