]> git.proxmox.com Git - rustc.git/blame - vendor/parking_lot/src/deadlock.rs
New upstream version 1.42.0+dfsg1
[rustc.git] / vendor / parking_lot / src / deadlock.rs
CommitLineData
b7449926 1//! \[Experimental\] Deadlock detection
83c7162d
XL
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 {
e1599b0c 43 use crate::{Mutex, ReentrantMutex, RwLock};
83c7162d 44 use std::sync::{Arc, Barrier};
b7449926 45 use std::thread::{self, sleep};
83c7162d 46 use std::time::Duration;
e1599b0c
XL
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 }
83c7162d
XL
52
53 fn check_deadlock() -> bool {
54 use parking_lot_core::deadlock::check_deadlock;
55 !check_deadlock().is_empty()
56 }
57
58 #[test]
59 fn test_mutex_deadlock() {
e1599b0c
XL
60 let _guard = DEADLOCK_DETECTION_LOCK.lock();
61
83c7162d
XL
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]
104 fn test_mutex_deadlock_reentrant() {
e1599b0c
XL
105 let _guard = DEADLOCK_DETECTION_LOCK.lock();
106
83c7162d
XL
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]
123 fn test_remutex_deadlock() {
e1599b0c
XL
124 let _guard = DEADLOCK_DETECTION_LOCK.lock();
125
83c7162d
XL
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]
171 fn test_rwlock_deadlock() {
e1599b0c
XL
172 let _guard = DEADLOCK_DETECTION_LOCK.lock();
173
83c7162d
XL
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
e1599b0c 215 #[cfg(rwlock_deadlock_detection_not_supported)]
83c7162d
XL
216 #[test]
217 fn test_rwlock_deadlock_reentrant() {
e1599b0c
XL
218 let _guard = DEADLOCK_DETECTION_LOCK.lock();
219
83c7162d
XL
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}