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