4 use crate::panic::panic_any;
7 atomic::{AtomicBool, Ordering},
8 mpsc::{channel, Sender},
11 use crate::thread::{self, Scope, ThreadId};
12 use crate::time::Duration;
13 use crate::time::Instant;
15 // !!! These tests are dangerous. If something is buggy, they will hang, !!!
16 // !!! instead of exiting cleanly. This might wedge the buildbots. !!!
19 fn test_unnamed_thread() {
20 thread::spawn(move || {
21 assert!(thread::current().name().is_none());
25 .expect("thread panicked");
29 fn test_named_thread() {
31 .name("ada lovelace".to_string())
33 assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
41 // Note: musl didn't add pthread_getname_np until 1.2.3
42 all(target_os = "linux", target_env = "gnu"),
48 fn test_named_thread_truncation() {
51 let long_name = crate::iter::once("test_named_thread_truncation")
52 .chain(crate::iter::repeat(" yada").take(100))
55 let result = Builder::new().name(long_name.clone()).spawn(move || {
56 // Rust remembers the full thread name itself.
57 assert_eq!(thread::current().name(), Some(long_name.as_str()));
59 // But the system is limited -- make sure we successfully set a truncation.
60 let mut buf = vec![0u8; long_name.len() + 1];
62 libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len());
64 let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
65 assert!(cstr.to_bytes().len() > 0);
66 assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
68 result.unwrap().join().unwrap();
73 fn test_invalid_named_thread() {
74 let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
79 let (tx, rx) = channel();
80 thread::spawn(move || {
87 fn test_is_finished() {
88 let b = Arc::new(Barrier::new(2));
89 let t = thread::spawn({
97 // Thread is definitely running here, since it's still waiting for the barrier.
98 assert_eq!(t.is_finished(), false);
100 // Unblock the barrier.
103 // Now check that t.is_finished() becomes true within a reasonable time.
104 let start = Instant::now();
105 while !t.is_finished() {
106 assert!(start.elapsed() < Duration::from_secs(2));
107 thread::sleep(Duration::from_millis(15));
110 // Joining the thread should not block for a significant time now.
111 let join_time = Instant::now();
112 assert_eq!(t.join().unwrap(), 1234);
113 assert!(join_time.elapsed() < Duration::from_secs(2));
117 fn test_join_panic() {
118 match thread::spawn(move || panic!()).join() {
119 result::Result::Err(_) => (),
120 result::Result::Ok(()) => panic!(),
125 fn test_spawn_sched() {
126 let (tx, rx) = channel();
128 fn f(i: i32, tx: Sender<()>) {
130 thread::spawn(move || {
132 tx.send(()).unwrap();
143 fn test_spawn_sched_childs_on_default_sched() {
144 let (tx, rx) = channel();
146 thread::spawn(move || {
147 thread::spawn(move || {
148 tx.send(()).unwrap();
155 fn avoid_copying_the_body<F>(spawnfn: F)
157 F: FnOnce(Box<dyn Fn() + Send>),
159 let (tx, rx) = channel();
161 let x: Box<_> = Box::new(1);
162 let x_in_parent = (&*x) as *const i32 as usize;
164 spawnfn(Box::new(move || {
165 let x_in_child = (&*x) as *const i32 as usize;
166 tx.send(x_in_child).unwrap();
169 let x_in_child = rx.recv().unwrap();
170 assert_eq!(x_in_parent, x_in_child);
174 fn test_avoid_copying_the_body_spawn() {
175 avoid_copying_the_body(|v| {
176 thread::spawn(move || v());
181 fn test_avoid_copying_the_body_thread_spawn() {
182 avoid_copying_the_body(|f| {
183 thread::spawn(move || {
190 fn test_avoid_copying_the_body_join() {
191 avoid_copying_the_body(|f| {
192 let _ = thread::spawn(move || f()).join();
197 fn test_child_doesnt_ref_parent() {
198 // If the child refcounts the parent thread, this will stack overflow when
199 // climbing the thread tree to dereference each ancestor. (See #1789)
200 // (well, it would if the constant were 8000+ - I lowered it to be more
201 // valgrind-friendly. try this at home, instead..!)
202 const GENERATIONS: u32 = 16;
203 fn child_no(x: u32) -> Box<dyn Fn() + Send> {
204 return Box::new(move || {
206 thread::spawn(move || child_no(x + 1)());
210 thread::spawn(|| child_no(0)());
214 fn test_simple_newsched_spawn() {
215 thread::spawn(move || {});
219 fn test_try_panic_message_string_literal() {
220 match thread::spawn(move || {
221 panic!("static string");
226 type T = &'static str;
227 assert!(e.is::<T>());
228 assert_eq!(*e.downcast::<T>().unwrap(), "static string");
235 fn test_try_panic_any_message_owned_str() {
236 match thread::spawn(move || {
237 panic_any("owned string".to_string());
243 assert!(e.is::<T>());
244 assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
251 fn test_try_panic_any_message_any() {
252 match thread::spawn(move || {
253 panic_any(Box::new(413u16) as Box<dyn Any + Send>);
258 type T = Box<dyn Any + Send>;
259 assert!(e.is::<T>());
260 let any = e.downcast::<T>().unwrap();
261 assert!(any.is::<u16>());
262 assert_eq!(*any.downcast::<u16>().unwrap(), 413);
269 fn test_try_panic_any_message_unit_struct() {
272 match thread::spawn(move || panic_any(Juju)).join() {
273 Err(ref e) if e.is::<Juju>() => {}
274 Err(_) | Ok(()) => panic!(),
279 fn test_park_unpark_before() {
281 thread::current().unpark();
287 fn test_park_unpark_called_other_thread() {
289 let th = thread::current();
291 let _guard = thread::spawn(move || {
292 super::sleep(Duration::from_millis(50));
301 fn test_park_timeout_unpark_before() {
303 thread::current().unpark();
304 thread::park_timeout(Duration::from_millis(u32::MAX as u64));
309 fn test_park_timeout_unpark_not_called() {
311 thread::park_timeout(Duration::from_millis(10));
316 fn test_park_timeout_unpark_called_other_thread() {
318 let th = thread::current();
320 let _guard = thread::spawn(move || {
321 super::sleep(Duration::from_millis(50));
325 thread::park_timeout(Duration::from_millis(u32::MAX as u64));
330 fn sleep_ms_smoke() {
331 thread::sleep(Duration::from_millis(2));
335 fn test_size_of_option_thread_id() {
336 assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
340 fn test_thread_id_equal() {
341 assert!(thread::current().id() == thread::current().id());
345 fn test_thread_id_not_equal() {
346 let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
347 assert!(thread::current().id() != spawned_id);
351 fn test_scoped_threads_drop_result_before_join() {
352 let actually_finished = &AtomicBool::new(false);
353 struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
354 impl Drop for X<'_, '_> {
356 thread::sleep(Duration::from_millis(20));
357 let actually_finished = self.1;
358 self.0.spawn(move || {
359 thread::sleep(Duration::from_millis(20));
360 actually_finished.store(true, Ordering::Relaxed);
366 thread::sleep(Duration::from_millis(20));
367 X(s, actually_finished)
370 assert!(actually_finished.load(Ordering::Relaxed));
374 fn test_scoped_threads_nll() {
375 // this is mostly a *compilation test* for this exact function:
381 // let's also run it for good measure
386 // Regression test for https://github.com/rust-lang/rust/issues/98498.
388 #[cfg(miri)] // relies on Miri's data race detector
389 fn scope_join_race() {
391 let a_bool = AtomicBool::new(false);
395 s.spawn(|| a_bool.load(Ordering::Relaxed));
399 s.spawn(|| a_bool.load(Ordering::Relaxed));