]> git.lizzy.rs Git - rust.git/blob - library/std/src/thread/tests.rs
Auto merge of #96210 - nnethercote:speed-up-TokenCursor, r=petrochenkov
[rust.git] / library / std / src / thread / tests.rs
1 use super::Builder;
2 use crate::any::Any;
3 use crate::mem;
4 use crate::panic::panic_any;
5 use crate::result;
6 use crate::sync::{
7     atomic::{AtomicBool, Ordering},
8     mpsc::{channel, Sender},
9     Arc, Barrier,
10 };
11 use crate::thread::{self, Scope, ThreadId};
12 use crate::time::Duration;
13 use crate::time::Instant;
14
15 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
16 // !!! instead of exiting cleanly. This might wedge the buildbots.       !!!
17
18 #[test]
19 fn test_unnamed_thread() {
20     thread::spawn(move || {
21         assert!(thread::current().name().is_none());
22     })
23     .join()
24     .ok()
25     .expect("thread panicked");
26 }
27
28 #[test]
29 fn test_named_thread() {
30     Builder::new()
31         .name("ada lovelace".to_string())
32         .spawn(move || {
33             assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
34         })
35         .unwrap()
36         .join()
37         .unwrap();
38 }
39
40 #[test]
41 #[should_panic]
42 fn test_invalid_named_thread() {
43     let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
44 }
45
46 #[test]
47 fn test_run_basic() {
48     let (tx, rx) = channel();
49     thread::spawn(move || {
50         tx.send(()).unwrap();
51     });
52     rx.recv().unwrap();
53 }
54
55 #[test]
56 fn test_is_finished() {
57     let b = Arc::new(Barrier::new(2));
58     let t = thread::spawn({
59         let b = b.clone();
60         move || {
61             b.wait();
62             1234
63         }
64     });
65
66     // Thread is definitely running here, since it's still waiting for the barrier.
67     assert_eq!(t.is_finished(), false);
68
69     // Unblock the barrier.
70     b.wait();
71
72     // Now check that t.is_finished() becomes true within a reasonable time.
73     let start = Instant::now();
74     while !t.is_finished() {
75         assert!(start.elapsed() < Duration::from_secs(2));
76         thread::sleep(Duration::from_millis(15));
77     }
78
79     // Joining the thread should not block for a significant time now.
80     let join_time = Instant::now();
81     assert_eq!(t.join().unwrap(), 1234);
82     assert!(join_time.elapsed() < Duration::from_secs(2));
83 }
84
85 #[test]
86 fn test_join_panic() {
87     match thread::spawn(move || panic!()).join() {
88         result::Result::Err(_) => (),
89         result::Result::Ok(()) => panic!(),
90     }
91 }
92
93 #[test]
94 fn test_spawn_sched() {
95     let (tx, rx) = channel();
96
97     fn f(i: i32, tx: Sender<()>) {
98         let tx = tx.clone();
99         thread::spawn(move || {
100             if i == 0 {
101                 tx.send(()).unwrap();
102             } else {
103                 f(i - 1, tx);
104             }
105         });
106     }
107     f(10, tx);
108     rx.recv().unwrap();
109 }
110
111 #[test]
112 fn test_spawn_sched_childs_on_default_sched() {
113     let (tx, rx) = channel();
114
115     thread::spawn(move || {
116         thread::spawn(move || {
117             tx.send(()).unwrap();
118         });
119     });
120
121     rx.recv().unwrap();
122 }
123
124 fn avoid_copying_the_body<F>(spawnfn: F)
125 where
126     F: FnOnce(Box<dyn Fn() + Send>),
127 {
128     let (tx, rx) = channel();
129
130     let x: Box<_> = box 1;
131     let x_in_parent = (&*x) as *const i32 as usize;
132
133     spawnfn(Box::new(move || {
134         let x_in_child = (&*x) as *const i32 as usize;
135         tx.send(x_in_child).unwrap();
136     }));
137
138     let x_in_child = rx.recv().unwrap();
139     assert_eq!(x_in_parent, x_in_child);
140 }
141
142 #[test]
143 fn test_avoid_copying_the_body_spawn() {
144     avoid_copying_the_body(|v| {
145         thread::spawn(move || v());
146     });
147 }
148
149 #[test]
150 fn test_avoid_copying_the_body_thread_spawn() {
151     avoid_copying_the_body(|f| {
152         thread::spawn(move || {
153             f();
154         });
155     })
156 }
157
158 #[test]
159 fn test_avoid_copying_the_body_join() {
160     avoid_copying_the_body(|f| {
161         let _ = thread::spawn(move || f()).join();
162     })
163 }
164
165 #[test]
166 fn test_child_doesnt_ref_parent() {
167     // If the child refcounts the parent thread, this will stack overflow when
168     // climbing the thread tree to dereference each ancestor. (See #1789)
169     // (well, it would if the constant were 8000+ - I lowered it to be more
170     // valgrind-friendly. try this at home, instead..!)
171     const GENERATIONS: u32 = 16;
172     fn child_no(x: u32) -> Box<dyn Fn() + Send> {
173         return Box::new(move || {
174             if x < GENERATIONS {
175                 thread::spawn(move || child_no(x + 1)());
176             }
177         });
178     }
179     thread::spawn(|| child_no(0)());
180 }
181
182 #[test]
183 fn test_simple_newsched_spawn() {
184     thread::spawn(move || {});
185 }
186
187 #[test]
188 fn test_try_panic_message_string_literal() {
189     match thread::spawn(move || {
190         panic!("static string");
191     })
192     .join()
193     {
194         Err(e) => {
195             type T = &'static str;
196             assert!(e.is::<T>());
197             assert_eq!(*e.downcast::<T>().unwrap(), "static string");
198         }
199         Ok(()) => panic!(),
200     }
201 }
202
203 #[test]
204 fn test_try_panic_any_message_owned_str() {
205     match thread::spawn(move || {
206         panic_any("owned string".to_string());
207     })
208     .join()
209     {
210         Err(e) => {
211             type T = String;
212             assert!(e.is::<T>());
213             assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
214         }
215         Ok(()) => panic!(),
216     }
217 }
218
219 #[test]
220 fn test_try_panic_any_message_any() {
221     match thread::spawn(move || {
222         panic_any(box 413u16 as Box<dyn Any + Send>);
223     })
224     .join()
225     {
226         Err(e) => {
227             type T = Box<dyn Any + Send>;
228             assert!(e.is::<T>());
229             let any = e.downcast::<T>().unwrap();
230             assert!(any.is::<u16>());
231             assert_eq!(*any.downcast::<u16>().unwrap(), 413);
232         }
233         Ok(()) => panic!(),
234     }
235 }
236
237 #[test]
238 fn test_try_panic_any_message_unit_struct() {
239     struct Juju;
240
241     match thread::spawn(move || panic_any(Juju)).join() {
242         Err(ref e) if e.is::<Juju>() => {}
243         Err(_) | Ok(()) => panic!(),
244     }
245 }
246
247 #[test]
248 fn test_park_timeout_unpark_before() {
249     for _ in 0..10 {
250         thread::current().unpark();
251         thread::park_timeout(Duration::from_millis(u32::MAX as u64));
252     }
253 }
254
255 #[test]
256 fn test_park_timeout_unpark_not_called() {
257     for _ in 0..10 {
258         thread::park_timeout(Duration::from_millis(10));
259     }
260 }
261
262 #[test]
263 fn test_park_timeout_unpark_called_other_thread() {
264     for _ in 0..10 {
265         let th = thread::current();
266
267         let _guard = thread::spawn(move || {
268             super::sleep(Duration::from_millis(50));
269             th.unpark();
270         });
271
272         thread::park_timeout(Duration::from_millis(u32::MAX as u64));
273     }
274 }
275
276 #[test]
277 fn sleep_ms_smoke() {
278     thread::sleep(Duration::from_millis(2));
279 }
280
281 #[test]
282 fn test_size_of_option_thread_id() {
283     assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
284 }
285
286 #[test]
287 fn test_thread_id_equal() {
288     assert!(thread::current().id() == thread::current().id());
289 }
290
291 #[test]
292 fn test_thread_id_not_equal() {
293     let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
294     assert!(thread::current().id() != spawned_id);
295 }
296
297 #[test]
298 fn test_scoped_threads_drop_result_before_join() {
299     let actually_finished = &AtomicBool::new(false);
300     struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
301     impl Drop for X<'_, '_> {
302         fn drop(&mut self) {
303             thread::sleep(Duration::from_millis(20));
304             let actually_finished = self.1;
305             self.0.spawn(move || {
306                 thread::sleep(Duration::from_millis(20));
307                 actually_finished.store(true, Ordering::Relaxed);
308             });
309         }
310     }
311     thread::scope(|s| {
312         s.spawn(move || {
313             thread::sleep(Duration::from_millis(20));
314             X(s, actually_finished)
315         });
316     });
317     assert!(actually_finished.load(Ordering::Relaxed));
318 }