Skip to main content

parking_lot/
deadlock.rs

1//! \[Experimental\] Deadlock detection
2//!
3//! This feature is optional and can be enabled with the `deadlock_detection`
4//! Cargo feature.
5//!
6//! Reporting is destructive: detected threads are removed from their parking
7//! queues, capture their backtraces, and then remain blocked permanently.
8//! Waits with a deadline are not reported because they can resolve by timing
9//! out.
10//!
11//! # Example
12//!
13//! ```
14//! #[cfg(feature = "deadlock_detection")]
15//! { // only for #[cfg]
16//! use std::thread;
17//! use std::time::Duration;
18//! use parking_lot::deadlock;
19//!
20//! // Create a background thread which checks for deadlocks every 10s
21//! thread::spawn(move || {
22//!     loop {
23//!         thread::sleep(Duration::from_secs(10));
24//!         let deadlocks = deadlock::check_deadlock();
25//!         if deadlocks.is_empty() {
26//!             continue;
27//!         }
28//!
29//!         println!("{} deadlocks detected", deadlocks.len());
30//!         for (i, threads) in deadlocks.iter().enumerate() {
31//!             println!("Deadlock #{}", i);
32//!             for t in threads {
33//!                 println!("Thread ID {:#?}", t.thread_id());
34//!                 println!("{:#?}", t.backtrace());
35//!             }
36//!         }
37//!     }
38//! });
39//! } // only for #[cfg]
40//! ```
41
42#[cfg(feature = "deadlock_detection")]
43pub use parking_lot_core::deadlock::check_deadlock;
44
45// Gate these on our deadlock_detection feature instead of the one in
46// parking_lot_core.
47//
48// This is necessary to enforce the incompatibility of deadlock detection with
49// the send_guard feature.
50#[inline]
51pub(crate) unsafe fn acquire_resource(key: usize) {
52    if falsecfg!(feature = "deadlock_detection") {
53        unsafe {
54            parking_lot_core::deadlock::acquire_resource(key);
55        }
56    }
57}
58#[inline]
59pub(crate) unsafe fn release_resource(key: usize) {
60    if falsecfg!(feature = "deadlock_detection") {
61        unsafe {
62            parking_lot_core::deadlock::release_resource(key);
63        }
64    }
65}
66
67#[cfg(test)]
68#[cfg(feature = "deadlock_detection")]
69mod tests {
70    use crate::{Mutex, Once, ReentrantMutex, RwLock};
71    use std::sync::{Arc, Barrier, mpsc};
72    use std::thread::{self, sleep};
73    use std::time::Duration;
74
75    // Serialize these tests with each other because deadlock detection scans
76    // and mutates process-global parking queues.
77    static DEADLOCK_DETECTION_LOCK: Mutex<()> = Mutex::new(());
78
79    fn check_deadlock() -> bool {
80        use parking_lot_core::deadlock::check_deadlock;
81        !check_deadlock().is_empty()
82    }
83
84    #[track_caller]
85    fn assert_deadlock(thread_count: usize) {
86        let deadlocks = parking_lot_core::deadlock::check_deadlock();
87        assert_eq!(deadlocks.len(), 1);
88        assert_eq!(deadlocks[0].len(), thread_count);
89    }
90
91    #[test]
92    fn test_mutex_deadlock() {
93        let _guard = DEADLOCK_DETECTION_LOCK.lock();
94
95        let m1: Arc<Mutex<()>> = Default::default();
96        let m2: Arc<Mutex<()>> = Default::default();
97        let m3: Arc<Mutex<()>> = Default::default();
98        let b = Arc::new(Barrier::new(4));
99
100        let m1_ = m1.clone();
101        let m2_ = m2.clone();
102        let m3_ = m3.clone();
103        let b1 = b.clone();
104        let b2 = b.clone();
105        let b3 = b.clone();
106
107        assert!(!check_deadlock());
108
109        let _t1 = thread::spawn(move || {
110            let _g = m1.lock();
111            b1.wait();
112            let _blocked = m2_.lock();
113        });
114
115        let _t2 = thread::spawn(move || {
116            let _g = m2.lock();
117            b2.wait();
118            let _blocked = m3_.lock();
119        });
120
121        let _t3 = thread::spawn(move || {
122            let _g = m3.lock();
123            b3.wait();
124            let _blocked = m1_.lock();
125        });
126
127        assert!(!check_deadlock());
128
129        b.wait();
130        sleep(Duration::from_millis(50));
131        assert_deadlock(3);
132
133        assert!(!check_deadlock());
134    }
135
136    #[test]
137    fn test_mutex_deadlock_reentrant() {
138        let _guard = DEADLOCK_DETECTION_LOCK.lock();
139
140        let m1: Arc<Mutex<()>> = Default::default();
141
142        assert!(!check_deadlock());
143
144        let _t1 = thread::spawn(move || {
145            let _g = m1.lock();
146            let _blocked = m1.lock();
147        });
148
149        sleep(Duration::from_millis(50));
150        assert_deadlock(1);
151
152        assert!(!check_deadlock());
153    }
154
155    #[test]
156    fn test_once_deadlock() {
157        let _guard = DEADLOCK_DETECTION_LOCK.lock();
158
159        let once = Arc::new(Once::new());
160        let mutex = Arc::new(Mutex::new(()));
161        let barrier = Arc::new(Barrier::new(2));
162
163        let once1 = Arc::clone(&once);
164        let mutex1 = Arc::clone(&mutex);
165        let barrier1 = Arc::clone(&barrier);
166        let _t1 = thread::spawn(move || {
167            once1.call_once(|| {
168                barrier1.wait();
169                let _blocked = mutex1.lock();
170            });
171        });
172
173        let barrier2 = Arc::clone(&barrier);
174        let _t2 = thread::spawn(move || {
175            let _guard = mutex.lock();
176            barrier2.wait();
177            once.call_once(|| unreachable!());
178        });
179
180        sleep(Duration::from_millis(50));
181        assert_deadlock(2);
182        assert!(!check_deadlock());
183    }
184
185    #[test]
186    fn test_remutex_deadlock() {
187        let _guard = DEADLOCK_DETECTION_LOCK.lock();
188
189        let m1: Arc<ReentrantMutex<()>> = Default::default();
190        let m2: Arc<ReentrantMutex<()>> = Default::default();
191        let m3: Arc<ReentrantMutex<()>> = Default::default();
192        let b = Arc::new(Barrier::new(4));
193
194        let m1_ = m1.clone();
195        let m2_ = m2.clone();
196        let m3_ = m3.clone();
197        let b1 = b.clone();
198        let b2 = b.clone();
199        let b3 = b.clone();
200
201        assert!(!check_deadlock());
202
203        let _t1 = thread::spawn(move || {
204            let _g = m1.lock();
205            let _g = m1.lock();
206            b1.wait();
207            let _ = m2_.lock();
208        });
209
210        let _t2 = thread::spawn(move || {
211            let _g = m2.lock();
212            let _g = m2.lock();
213            b2.wait();
214            let _ = m3_.lock();
215        });
216
217        let _t3 = thread::spawn(move || {
218            let _g = m3.lock();
219            let _g = m3.lock();
220            b3.wait();
221            let _ = m1_.lock();
222        });
223
224        assert!(!check_deadlock());
225
226        b.wait();
227        sleep(Duration::from_millis(50));
228        assert_deadlock(3);
229
230        assert!(!check_deadlock());
231    }
232
233    #[test]
234    fn test_rwlock_deadlock() {
235        let _guard = DEADLOCK_DETECTION_LOCK.lock();
236
237        let m1: Arc<RwLock<()>> = Default::default();
238        let m2: Arc<RwLock<()>> = Default::default();
239        let m3: Arc<RwLock<()>> = Default::default();
240        let b = Arc::new(Barrier::new(4));
241
242        let m1_ = m1.clone();
243        let m2_ = m2.clone();
244        let m3_ = m3.clone();
245        let b1 = b.clone();
246        let b2 = b.clone();
247        let b3 = b.clone();
248
249        assert!(!check_deadlock());
250
251        let _t1 = thread::spawn(move || {
252            let _g = m1.read();
253            b1.wait();
254            let _g = m2_.write();
255        });
256
257        let _t2 = thread::spawn(move || {
258            let _g = m2.read();
259            b2.wait();
260            let _g = m3_.write();
261        });
262
263        let _t3 = thread::spawn(move || {
264            let _g = m3.read();
265            b3.wait();
266            let _blocked = m1_.write();
267        });
268
269        assert!(!check_deadlock());
270
271        b.wait();
272        sleep(Duration::from_millis(50));
273        assert_deadlock(3);
274
275        assert!(!check_deadlock());
276    }
277
278    #[test]
279    fn test_rwlock_deadlock_reentrant() {
280        let _guard = DEADLOCK_DETECTION_LOCK.lock();
281
282        let m1: Arc<RwLock<()>> = Default::default();
283
284        assert!(!check_deadlock());
285
286        let _t1 = thread::spawn(move || {
287            let _g = m1.read();
288            let _ = m1.write();
289        });
290
291        sleep(Duration::from_millis(50));
292        assert_deadlock(1);
293
294        assert!(!check_deadlock());
295    }
296
297    #[test]
298    fn test_rwlock_shared_reader_does_not_own_primary_key() {
299        let _guard = DEADLOCK_DETECTION_LOCK.lock();
300
301        let rwlock: Arc<RwLock<()>> = Default::default();
302        let mutex: Arc<Mutex<()>> = Default::default();
303        let (upgradable_ready_tx, upgradable_ready_rx) = mpsc::channel();
304        let (release_upgradable_tx, release_upgradable_rx) = mpsc::channel();
305        let (reader_ready_tx, reader_ready_rx) = mpsc::channel();
306
307        let rwlock1 = Arc::clone(&rwlock);
308        let upgradable = thread::spawn(move || {
309            let _guard = rwlock1.upgradable_read();
310            upgradable_ready_tx.send(()).unwrap();
311            release_upgradable_rx.recv().unwrap();
312        });
313        upgradable_ready_rx.recv().unwrap();
314
315        let rwlock2 = Arc::clone(&rwlock);
316        let mutex1 = Arc::clone(&mutex);
317        let blocked_upgradable = thread::spawn(move || {
318            let _guard = mutex1.lock();
319            let _blocked = rwlock2.upgradable_read();
320        });
321        while !unsafe { rwlock.raw() }.has_parked_threads() {
322            thread::yield_now();
323        }
324
325        let rwlock3 = Arc::clone(&rwlock);
326        let mutex2 = Arc::clone(&mutex);
327        let reader = thread::spawn(move || {
328            let _guard = rwlock3.read();
329            reader_ready_tx.send(()).unwrap();
330            let _blocked = mutex2.lock();
331        });
332        reader_ready_rx.recv().unwrap();
333
334        sleep(Duration::from_millis(50));
335        assert!(!check_deadlock());
336
337        release_upgradable_tx.send(()).unwrap();
338        upgradable.join().unwrap();
339        blocked_upgradable.join().unwrap();
340        reader.join().unwrap();
341    }
342
343    #[test]
344    fn test_rwlock_pending_writer_owns_primary_key() {
345        let _guard = DEADLOCK_DETECTION_LOCK.lock();
346
347        let rwlock: Arc<RwLock<()>> = Default::default();
348        let mutex: Arc<Mutex<()>> = Default::default();
349        let (reader_ready_tx, reader_ready_rx) = mpsc::channel();
350        let (block_reader_tx, block_reader_rx) = mpsc::channel();
351        let (mutex_ready_tx, mutex_ready_rx) = mpsc::channel();
352
353        let rwlock1 = Arc::clone(&rwlock);
354        let mutex1 = Arc::clone(&mutex);
355        let _reader = thread::spawn(move || {
356            let _guard = rwlock1.read();
357            reader_ready_tx.send(()).unwrap();
358            block_reader_rx.recv().unwrap();
359            let _blocked = mutex1.lock();
360        });
361        reader_ready_rx.recv().unwrap();
362
363        let rwlock2 = Arc::clone(&rwlock);
364        let _writer = thread::spawn(move || {
365            let _blocked = rwlock2.write();
366        });
367        while !unsafe { rwlock.raw() }.has_parked_threads() {
368            thread::yield_now();
369        }
370
371        let rwlock3 = Arc::clone(&rwlock);
372        let _blocked_reader = thread::spawn(move || {
373            let _guard = mutex.lock();
374            mutex_ready_tx.send(()).unwrap();
375            let _blocked = rwlock3.read();
376        });
377        mutex_ready_rx.recv().unwrap();
378        block_reader_tx.send(()).unwrap();
379
380        sleep(Duration::from_millis(50));
381        assert_deadlock(3);
382        assert!(!check_deadlock());
383    }
384}