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