parking_lot/
deadlock.rs

1//! \[Experimental\] Deadlock detection
2//!
3//! This feature is optional and can be enabled via the `deadlock_detection` feature flag.
4//!
5//! # Example
6//!
7//! ```
8//! #[cfg(feature = "deadlock_detection")]
9//! { // only for #[cfg]
10//! use std::thread;
11//! use std::time::Duration;
12//! use parking_lot::deadlock;
13//!
14//! // Create a background thread which checks for deadlocks every 10s
15//! thread::spawn(move || {
16//!     loop {
17//!         thread::sleep(Duration::from_secs(10));
18//!         let deadlocks = deadlock::check_deadlock();
19//!         if deadlocks.is_empty() {
20//!             continue;
21//!         }
22//!
23//!         println!("{} deadlocks detected", deadlocks.len());
24//!         for (i, threads) in deadlocks.iter().enumerate() {
25//!             println!("Deadlock #{}", i);
26//!             for t in threads {
27//!                 println!("Thread Id {:#?}", t.thread_id());
28//!                 println!("{:#?}", t.backtrace());
29//!             }
30//!         }
31//!     }
32//! });
33//! } // only for #[cfg]
34//! ```
35
36#[cfg(feature = "deadlock_detection")]
37pub use parking_lot_core::deadlock::check_deadlock;
38pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource};
39
40#[cfg(test)]
41#[cfg(feature = "deadlock_detection")]
42mod tests {
43    use crate::{Mutex, ReentrantMutex, RwLock};
44    use std::sync::{Arc, Barrier};
45    use std::thread::{self, sleep};
46    use std::time::Duration;
47
48    // We need to serialize these tests since deadlock detection uses global state
49    static DEADLOCK_DETECTION_LOCK: Mutex<()> = crate::const_mutex(());
50
51    fn check_deadlock() -> bool {
52        use parking_lot_core::deadlock::check_deadlock;
53        !check_deadlock().is_empty()
54    }
55
56    #[test]
57    fn test_mutex_deadlock() {
58        let _guard = DEADLOCK_DETECTION_LOCK.lock();
59
60        let m1: Arc<Mutex<()>> = Default::default();
61        let m2: Arc<Mutex<()>> = Default::default();
62        let m3: Arc<Mutex<()>> = Default::default();
63        let b = Arc::new(Barrier::new(4));
64
65        let m1_ = m1.clone();
66        let m2_ = m2.clone();
67        let m3_ = m3.clone();
68        let b1 = b.clone();
69        let b2 = b.clone();
70        let b3 = b.clone();
71
72        assert!(!check_deadlock());
73
74        let _t1 = thread::spawn(move || {
75            let _g = m1.lock();
76            b1.wait();
77            let _ = m2_.lock();
78        });
79
80        let _t2 = thread::spawn(move || {
81            let _g = m2.lock();
82            b2.wait();
83            let _ = m3_.lock();
84        });
85
86        let _t3 = thread::spawn(move || {
87            let _g = m3.lock();
88            b3.wait();
89            let _ = m1_.lock();
90        });
91
92        assert!(!check_deadlock());
93
94        b.wait();
95        sleep(Duration::from_millis(50));
96        assert!(check_deadlock());
97
98        assert!(!check_deadlock());
99    }
100
101    #[test]
102    fn test_mutex_deadlock_reentrant() {
103        let _guard = DEADLOCK_DETECTION_LOCK.lock();
104
105        let m1: Arc<Mutex<()>> = Default::default();
106
107        assert!(!check_deadlock());
108
109        let _t1 = thread::spawn(move || {
110            let _g = m1.lock();
111            let _ = m1.lock();
112        });
113
114        sleep(Duration::from_millis(50));
115        assert!(check_deadlock());
116
117        assert!(!check_deadlock());
118    }
119
120    #[test]
121    fn test_remutex_deadlock() {
122        let _guard = DEADLOCK_DETECTION_LOCK.lock();
123
124        let m1: Arc<ReentrantMutex<()>> = Default::default();
125        let m2: Arc<ReentrantMutex<()>> = Default::default();
126        let m3: Arc<ReentrantMutex<()>> = Default::default();
127        let b = Arc::new(Barrier::new(4));
128
129        let m1_ = m1.clone();
130        let m2_ = m2.clone();
131        let m3_ = m3.clone();
132        let b1 = b.clone();
133        let b2 = b.clone();
134        let b3 = b.clone();
135
136        assert!(!check_deadlock());
137
138        let _t1 = thread::spawn(move || {
139            let _g = m1.lock();
140            let _g = m1.lock();
141            b1.wait();
142            let _ = m2_.lock();
143        });
144
145        let _t2 = thread::spawn(move || {
146            let _g = m2.lock();
147            let _g = m2.lock();
148            b2.wait();
149            let _ = m3_.lock();
150        });
151
152        let _t3 = thread::spawn(move || {
153            let _g = m3.lock();
154            let _g = m3.lock();
155            b3.wait();
156            let _ = m1_.lock();
157        });
158
159        assert!(!check_deadlock());
160
161        b.wait();
162        sleep(Duration::from_millis(50));
163        assert!(check_deadlock());
164
165        assert!(!check_deadlock());
166    }
167
168    #[test]
169    fn test_rwlock_deadlock() {
170        let _guard = DEADLOCK_DETECTION_LOCK.lock();
171
172        let m1: Arc<RwLock<()>> = Default::default();
173        let m2: Arc<RwLock<()>> = Default::default();
174        let m3: Arc<RwLock<()>> = Default::default();
175        let b = Arc::new(Barrier::new(4));
176
177        let m1_ = m1.clone();
178        let m2_ = m2.clone();
179        let m3_ = m3.clone();
180        let b1 = b.clone();
181        let b2 = b.clone();
182        let b3 = b.clone();
183
184        assert!(!check_deadlock());
185
186        let _t1 = thread::spawn(move || {
187            let _g = m1.read();
188            b1.wait();
189            let _g = m2_.write();
190        });
191
192        let _t2 = thread::spawn(move || {
193            let _g = m2.read();
194            b2.wait();
195            let _g = m3_.write();
196        });
197
198        let _t3 = thread::spawn(move || {
199            let _g = m3.read();
200            b3.wait();
201            let _ = m1_.write();
202        });
203
204        assert!(!check_deadlock());
205
206        b.wait();
207        sleep(Duration::from_millis(50));
208        assert!(check_deadlock());
209
210        assert!(!check_deadlock());
211    }
212
213    #[cfg(rwlock_deadlock_detection_not_supported)]
214    #[test]
215    fn test_rwlock_deadlock_reentrant() {
216        let _guard = DEADLOCK_DETECTION_LOCK.lock();
217
218        let m1: Arc<RwLock<()>> = Default::default();
219
220        assert!(!check_deadlock());
221
222        let _t1 = thread::spawn(move || {
223            let _g = m1.read();
224            let _ = m1.write();
225        });
226
227        sleep(Duration::from_millis(50));
228        assert!(check_deadlock());
229
230        assert!(!check_deadlock());
231    }
232}