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}
233