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     static DEADLOCK_DETECTION_LOCK: Mutex<()> = crate::const_mutex(());
50 
check_deadlock() -> bool51     fn check_deadlock() -> bool {
52         use parking_lot_core::deadlock::check_deadlock;
53         !check_deadlock().is_empty()
54     }
55 
56     #[test]
test_mutex_deadlock()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]
test_mutex_deadlock_reentrant()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]
test_remutex_deadlock()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]
test_rwlock_deadlock()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]
test_rwlock_deadlock_reentrant()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 }
233