1use std::collections::{HashMap, HashSet};
21use std::sync::Mutex;
22use std::time::{Duration, Instant};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum LockType {
27 Mutex,
29 RwLockRead,
31 RwLockWrite,
33 Semaphore,
35}
36
37impl LockType {
38 pub fn as_str(&self) -> &'static str {
40 match self {
41 LockType::Mutex => "mutex",
42 LockType::RwLockRead => "rwlock_read",
43 LockType::RwLockWrite => "rwlock_write",
44 LockType::Semaphore => "semaphore",
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
51pub struct LockInfo {
52 pub id: u64,
54 pub lock_type: LockType,
56 pub owner: Option<u64>,
58 pub waiters: Vec<u64>,
60 pub acquired_at: Option<Instant>,
62}
63
64impl LockInfo {
65 pub fn new(id: u64, lock_type: LockType) -> Self {
67 Self {
68 id,
69 lock_type,
70 owner: None,
71 waiters: Vec::new(),
72 acquired_at: None,
73 }
74 }
75
76 pub fn is_held(&self) -> bool {
78 self.owner.is_some()
79 }
80
81 pub fn hold_duration(&self) -> Option<Duration> {
83 self.acquired_at.map(|t| t.elapsed())
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Hash)]
89pub struct WaitGraphEdge {
90 pub waiter: u64,
92 pub waited_for: u64,
94 pub lock_id: u64,
96}
97
98#[derive(Debug, Clone)]
100pub struct DeadlockDetectorConfig {
101 pub detection_interval: Duration,
103 pub max_hold_time: Duration,
105 pub enabled: bool,
107}
108
109impl Default for DeadlockDetectorConfig {
110 fn default() -> Self {
111 Self {
112 detection_interval: Duration::from_secs(1),
113 max_hold_time: Duration::from_secs(30),
114 enabled: true,
115 }
116 }
117}
118
119pub struct DeadlockDetector {
127 config: DeadlockDetectorConfig,
129 locks: Mutex<HashMap<u64, LockInfo>>,
131 wait_graph: Mutex<Vec<WaitGraphEdge>>,
133 requests: Mutex<HashMap<String, u64>>,
135 next_lock_id: Mutex<u64>,
137}
138
139impl DeadlockDetector {
140 pub fn new(config: DeadlockDetectorConfig) -> Self {
142 Self {
143 config,
144 locks: Mutex::new(HashMap::new()),
145 wait_graph: Mutex::new(Vec::new()),
146 requests: Mutex::new(HashMap::new()),
147 next_lock_id: Mutex::new(0),
148 }
149 }
150
151 pub fn with_defaults() -> Self {
153 Self::new(DeadlockDetectorConfig::default())
154 }
155
156 pub fn config(&self) -> &DeadlockDetectorConfig {
158 &self.config
159 }
160
161 pub fn register_lock(&self, lock_type: LockType) -> u64 {
163 let id = {
164 let mut next = self.next_lock_id.lock().unwrap_or_else(|e| e.into_inner());
165 *next += 1;
166 *next
167 };
168
169 let info = LockInfo::new(id, lock_type);
170 if let Ok(mut locks) = self.locks.lock() {
171 locks.insert(id, info);
172 }
173
174 id
175 }
176
177 pub fn unregister_lock(&self, lock_id: u64) {
179 if let Ok(mut locks) = self.locks.lock() {
180 locks.remove(&lock_id);
181 }
182 }
183
184 pub fn record_acquire(&self, lock_id: u64, thread_id: u64) {
186 if !self.config.enabled {
187 return;
188 }
189
190 if let Ok(mut locks) = self.locks.lock()
191 && let Some(info) = locks.get_mut(&lock_id)
192 {
193 info.owner = Some(thread_id);
194 info.acquired_at = Some(Instant::now());
195 info.waiters.retain(|&w| w != thread_id);
196 }
197
198 if let Ok(mut graph) = self.wait_graph.lock() {
200 graph.retain(|e| !(e.waiter == thread_id && e.lock_id == lock_id));
201 }
202 }
203
204 pub fn record_release(&self, lock_id: u64) {
206 if !self.config.enabled {
207 return;
208 }
209
210 if let Ok(mut locks) = self.locks.lock()
211 && let Some(info) = locks.get_mut(&lock_id)
212 {
213 info.owner = None;
214 info.acquired_at = None;
215 }
216 }
217
218 pub fn record_wait(&self, lock_id: u64, thread_id: u64) {
220 if !self.config.enabled {
221 return;
222 }
223
224 if let Ok(mut locks) = self.locks.lock()
226 && let Some(info) = locks.get_mut(&lock_id)
227 {
228 if !info.waiters.contains(&thread_id) {
229 info.waiters.push(thread_id);
230 }
231
232 if let Some(owner) = info.owner
234 && owner != thread_id
235 && let Ok(mut graph) = self.wait_graph.lock()
236 {
237 graph.push(WaitGraphEdge {
238 waiter: thread_id,
239 waited_for: owner,
240 lock_id,
241 });
242 }
243 }
244 }
245
246 pub fn detect_deadlock(&self) -> Option<Vec<u64>> {
248 if !self.config.enabled {
249 return None;
250 }
251
252 let graph = match self.wait_graph.lock() {
253 Ok(g) => g,
254 Err(_) => return None,
255 };
256
257 let mut adj: HashMap<u64, Vec<u64>> = HashMap::new();
259 for edge in graph.iter() {
260 adj.entry(edge.waiter).or_default().push(edge.waited_for);
261 }
262
263 let mut visited: HashSet<u64> = HashSet::new();
265 let mut rec_stack: HashSet<u64> = HashSet::new();
266 let mut path: Vec<u64> = Vec::new();
267
268 for &node in adj.keys() {
269 if self.dfs_cycle(node, &adj, &mut visited, &mut rec_stack, &mut path) {
270 return Some(path);
271 }
272 }
273
274 None
275 }
276
277 fn dfs_cycle(
279 &self,
280 node: u64,
281 adj: &HashMap<u64, Vec<u64>>,
282 visited: &mut HashSet<u64>,
283 rec_stack: &mut HashSet<u64>,
284 path: &mut Vec<u64>,
285 ) -> bool {
286 if rec_stack.contains(&node) {
287 if let Some(start) = path.iter().position(|&n| n == node) {
289 *path = path[start..].to_vec();
290 }
291 path.push(node);
292 return true;
293 }
294
295 if visited.contains(&node) {
296 return false;
297 }
298
299 visited.insert(node);
300 rec_stack.insert(node);
301 path.push(node);
302
303 if let Some(neighbors) = adj.get(&node) {
304 for &neighbor in neighbors {
305 if self.dfs_cycle(neighbor, adj, visited, rec_stack, path) {
306 return true;
307 }
308 }
309 }
310
311 rec_stack.remove(&node);
312 path.pop();
313 false
314 }
315
316 pub fn check_long_held(&self) -> Vec<(u64, Duration)> {
318 if !self.config.enabled {
319 return Vec::new();
320 }
321
322 let locks = match self.locks.lock() {
323 Ok(l) => l,
324 Err(_) => return Vec::new(),
325 };
326 let mut result = Vec::new();
327
328 for (&id, info) in locks.iter() {
329 if let Some(duration) = info.hold_duration()
330 && duration > self.config.max_hold_time
331 {
332 result.push((id, duration));
333 }
334 }
335
336 result
337 }
338
339 pub fn register_request(&self, request_id: &str, thread_id: u64) {
341 if let Ok(mut requests) = self.requests.lock() {
342 requests.insert(request_id.to_string(), thread_id);
343 }
344 }
345
346 pub fn unregister_request(&self, request_id: &str) {
348 if let Ok(mut requests) = self.requests.lock() {
349 requests.remove(request_id);
350 }
351 }
352
353 pub fn tracked_count(&self) -> usize {
355 if let Ok(requests) = self.requests.lock() {
356 requests.len()
357 } else {
358 0
359 }
360 }
361
362 pub fn get_lock_info(&self, lock_id: u64) -> Option<LockInfo> {
364 let locks = self.locks.lock().ok()?;
365 locks.get(&lock_id).cloned()
366 }
367
368 pub fn lock_count(&self) -> usize {
370 let locks = self.locks.lock().unwrap_or_else(|e| e.into_inner());
371 locks.len()
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378
379 #[test]
380 fn test_lock_info() {
381 let info = LockInfo::new(1, LockType::Mutex);
382 assert!(!info.is_held());
383 assert!(info.hold_duration().is_none());
384 }
385
386 #[test]
387 fn test_register_lock() {
388 let detector = DeadlockDetector::with_defaults();
389
390 let id1 = detector.register_lock(LockType::Mutex);
391 let id2 = detector.register_lock(LockType::RwLockWrite);
392
393 assert_ne!(id1, id2);
394 assert_eq!(detector.lock_count(), 2);
395
396 detector.unregister_lock(id1);
397 assert_eq!(detector.lock_count(), 1);
398 }
399
400 #[test]
401 fn test_acquire_release() {
402 let detector = DeadlockDetector::with_defaults();
403 let lock_id = detector.register_lock(LockType::Mutex);
404
405 detector.record_acquire(lock_id, 1);
406 let info = detector.get_lock_info(lock_id).unwrap();
407 assert!(info.is_held());
408 assert_eq!(info.owner, Some(1));
409
410 detector.record_release(lock_id);
411 let info = detector.get_lock_info(lock_id).unwrap();
412 assert!(!info.is_held());
413 }
414
415 #[test]
416 fn test_request_tracking() {
417 let detector = DeadlockDetector::with_defaults();
418
419 detector.register_request("req-1", 1);
420 detector.register_request("req-2", 2);
421 assert_eq!(detector.tracked_count(), 2);
422
423 detector.unregister_request("req-1");
424 assert_eq!(detector.tracked_count(), 1);
425 }
426
427 #[test]
428 fn test_no_deadlock() {
429 let detector = DeadlockDetector::with_defaults();
430
431 let lock1 = detector.register_lock(LockType::Mutex);
432 let lock2 = detector.register_lock(LockType::Mutex);
433
434 detector.record_acquire(lock1, 1);
436 detector.record_wait(lock2, 1);
437
438 detector.record_acquire(lock2, 2);
440
441 assert!(detector.detect_deadlock().is_none());
443 }
444
445 #[test]
446 fn test_disabled_detector() {
447 let config = DeadlockDetectorConfig {
448 enabled: false,
449 ..Default::default()
450 };
451 let detector = DeadlockDetector::new(config);
452
453 let lock_id = detector.register_lock(LockType::Mutex);
454 detector.record_acquire(lock_id, 1);
455
456 assert!(detector.detect_deadlock().is_none());
458 }
459}