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")]
37 pub use parking_lot_core::deadlock::check_deadlock;
38 pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource};
39 
40 #[cfg(test)]
41 #[cfg(feature = "deadlock_detection")]
42 mod 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     lazy_static::lazy_static! {
50         static ref DEADLOCK_DETECTION_LOCK: Mutex<()> = Mutex::new(());
51     }
52 
check_deadlock() -> bool53     fn check_deadlock() -> bool {
54         use parking_lot_core::deadlock::check_deadlock;
55         !check_deadlock().is_empty()
56     }
57 
58     #[test]
test_mutex_deadlock()59     fn test_mutex_deadlock() {
60         let _guard = DEADLOCK_DETECTION_LOCK.lock();
61 
62         let m1: Arc<Mutex<()>> = Default::default();
63         let m2: Arc<Mutex<()>> = Default::default();
64         let m3: Arc<Mutex<()>> = Default::default();
65         let b = Arc::new(Barrier::new(4));
66 
67         let m1_ = m1.clone();
68         let m2_ = m2.clone();
69         let m3_ = m3.clone();
70         let b1 = b.clone();
71         let b2 = b.clone();
72         let b3 = b.clone();
73 
74         assert!(!check_deadlock());
75 
76         let _t1 = thread::spawn(move || {
77             let _g = m1.lock();
78             b1.wait();
79             let _ = m2_.lock();
80         });
81 
82         let _t2 = thread::spawn(move || {
83             let _g = m2.lock();
84             b2.wait();
85             let _ = m3_.lock();
86         });
87 
88         let _t3 = thread::spawn(move || {
89             let _g = m3.lock();
90             b3.wait();
91             let _ = m1_.lock();
92         });
93 
94         assert!(!check_deadlock());
95 
96         b.wait();
97         sleep(Duration::from_millis(50));
98         assert!(check_deadlock());
99 
100         assert!(!check_deadlock());
101     }
102 
103     #[test]
test_mutex_deadlock_reentrant()104     fn test_mutex_deadlock_reentrant() {
105         let _guard = DEADLOCK_DETECTION_LOCK.lock();
106 
107         let m1: Arc<Mutex<()>> = Default::default();
108 
109         assert!(!check_deadlock());
110 
111         let _t1 = thread::spawn(move || {
112             let _g = m1.lock();
113             let _ = m1.lock();
114         });
115 
116         sleep(Duration::from_millis(50));
117         assert!(check_deadlock());
118 
119         assert!(!check_deadlock());
120     }
121 
122     #[test]
test_remutex_deadlock()123     fn test_remutex_deadlock() {
124         let _guard = DEADLOCK_DETECTION_LOCK.lock();
125 
126         let m1: Arc<ReentrantMutex<()>> = Default::default();
127         let m2: Arc<ReentrantMutex<()>> = Default::default();
128         let m3: Arc<ReentrantMutex<()>> = Default::default();
129         let b = Arc::new(Barrier::new(4));
130 
131         let m1_ = m1.clone();
132         let m2_ = m2.clone();
133         let m3_ = m3.clone();
134         let b1 = b.clone();
135         let b2 = b.clone();
136         let b3 = b.clone();
137 
138         assert!(!check_deadlock());
139 
140         let _t1 = thread::spawn(move || {
141             let _g = m1.lock();
142             let _g = m1.lock();
143             b1.wait();
144             let _ = m2_.lock();
145         });
146 
147         let _t2 = thread::spawn(move || {
148             let _g = m2.lock();
149             let _g = m2.lock();
150             b2.wait();
151             let _ = m3_.lock();
152         });
153 
154         let _t3 = thread::spawn(move || {
155             let _g = m3.lock();
156             let _g = m3.lock();
157             b3.wait();
158             let _ = m1_.lock();
159         });
160 
161         assert!(!check_deadlock());
162 
163         b.wait();
164         sleep(Duration::from_millis(50));
165         assert!(check_deadlock());
166 
167         assert!(!check_deadlock());
168     }
169 
170     #[test]
test_rwlock_deadlock()171     fn test_rwlock_deadlock() {
172         let _guard = DEADLOCK_DETECTION_LOCK.lock();
173 
174         let m1: Arc<RwLock<()>> = Default::default();
175         let m2: Arc<RwLock<()>> = Default::default();
176         let m3: Arc<RwLock<()>> = Default::default();
177         let b = Arc::new(Barrier::new(4));
178 
179         let m1_ = m1.clone();
180         let m2_ = m2.clone();
181         let m3_ = m3.clone();
182         let b1 = b.clone();
183         let b2 = b.clone();
184         let b3 = b.clone();
185 
186         assert!(!check_deadlock());
187 
188         let _t1 = thread::spawn(move || {
189             let _g = m1.read();
190             b1.wait();
191             let _g = m2_.write();
192         });
193 
194         let _t2 = thread::spawn(move || {
195             let _g = m2.read();
196             b2.wait();
197             let _g = m3_.write();
198         });
199 
200         let _t3 = thread::spawn(move || {
201             let _g = m3.read();
202             b3.wait();
203             let _ = m1_.write();
204         });
205 
206         assert!(!check_deadlock());
207 
208         b.wait();
209         sleep(Duration::from_millis(50));
210         assert!(check_deadlock());
211 
212         assert!(!check_deadlock());
213     }
214 
215     #[cfg(rwlock_deadlock_detection_not_supported)]
216     #[test]
test_rwlock_deadlock_reentrant()217     fn test_rwlock_deadlock_reentrant() {
218         let _guard = DEADLOCK_DETECTION_LOCK.lock();
219 
220         let m1: Arc<RwLock<()>> = Default::default();
221 
222         assert!(!check_deadlock());
223 
224         let _t1 = thread::spawn(move || {
225             let _g = m1.read();
226             let _ = m1.write();
227         });
228 
229         sleep(Duration::from_millis(50));
230         assert!(check_deadlock());
231 
232         assert!(!check_deadlock());
233     }
234 }
235