use crate::DeadlockInfo;
use crate::LockId;
use crate::ThreadId;
use crate::core::detector::DISPATCHER;
use crate::core::logger;
use crate::core::{DeadlockSource, Detector};
use chrono::Utc;
impl Detector {
pub fn filter_cycle_by_common_locks(&self, cycle: &[ThreadId]) -> Vec<ThreadId> {
if cycle.is_empty() {
return Vec::new();
}
let mut iter = cycle.iter();
let first = *iter.next().unwrap();
let mut intersection = self.thread_holds.get(&first).cloned().unwrap_or_default();
for &thread_id in iter {
if let Some(holds) = self.thread_holds.get(&thread_id) {
intersection = intersection.intersection(holds).copied().collect();
} else {
intersection.clear();
break;
}
}
if intersection.is_empty() {
cycle.to_vec()
} else {
Vec::new()
}
}
pub fn extract_deadlock_info(&self, cycle: Vec<ThreadId>) -> DeadlockInfo {
let thread_waiting_for_locks = cycle
.iter()
.filter_map(|&t| self.thread_waits_for.get(&t).map(|&l| (t, l)))
.collect();
DeadlockInfo {
source: DeadlockSource::WaitForGraph,
thread_cycle: cycle,
thread_waiting_for_locks,
lock_order_cycle: None,
timestamp: Utc::now().to_rfc3339(),
verification_request: None,
}
}
#[cfg(feature = "lock-order-graph")]
pub fn extract_lock_order_violation_info(
&self,
thread_id: ThreadId,
lock_id: LockId,
lock_cycle: Vec<LockId>,
) -> DeadlockInfo {
DeadlockInfo {
source: DeadlockSource::LockOrderViolation,
thread_cycle: vec![thread_id],
thread_waiting_for_locks: vec![(thread_id, lock_id)],
lock_order_cycle: Some(lock_cycle),
timestamp: Utc::now().to_rfc3339(),
verification_request: None,
}
}
}
pub fn process_deadlock(info: DeadlockInfo) {
DISPATCHER.send(info.clone());
logger::log_deadlock(info);
}
pub fn verify_deadlock_edges(
info: &DeadlockInfo,
thread_id: ThreadId,
lock_id: LockId,
expected_owner: ThreadId,
actual_owner: usize,
) -> bool {
let waiting_for_this = info
.thread_waiting_for_locks
.iter()
.any(|&(t, l)| t == thread_id && l == lock_id);
if !waiting_for_this {
return false;
}
if actual_owner != expected_owner {
return false; }
if info.source == DeadlockSource::LockOrderViolation {
return true;
}
let cycle_len = info.thread_cycle.len();
let mut self_index = None;
for (i, &t) in info.thread_cycle.iter().enumerate() {
if t == thread_id {
self_index = Some(i);
break;
}
}
if let Some(idx) = self_index {
let prev_idx = if idx == 0 { cycle_len - 1 } else { idx - 1 };
let prev_thread = info.thread_cycle[prev_idx];
let prev_waiting_for_this = info
.thread_waiting_for_locks
.iter()
.any(|&(t, l)| t == prev_thread && l == lock_id);
if prev_waiting_for_this {
return false; }
}
true
}