use crate::DeadlockInfo;
#[cfg(feature = "lock-order-graph")]
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;
}
}
intersection.retain(|lock_id| !self.rwlock_readers.contains_key(lock_id));
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(|intent| (t, intent.lock_id))
})
.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);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn common_shared_read_lock_does_not_filter_cycle() {
let mut detector = Detector::new();
detector.thread_holds.entry(1).or_default().insert(99);
detector.thread_holds.entry(2).or_default().insert(99);
detector.rwlock_readers.entry(99).or_default().insert(1, 1);
detector.rwlock_readers.entry(99).or_default().insert(2, 1);
assert_eq!(detector.filter_cycle_by_common_locks(&[1, 2]), vec![1, 2]);
}
}