263 lines
5.9 KiB
Rust
263 lines
5.9 KiB
Rust
|
|
use super::Builder;
|
||
|
|
use crate::any::Any;
|
||
|
|
use crate::mem;
|
||
|
|
use crate::result;
|
||
|
|
use crate::sync::mpsc::{channel, Sender};
|
||
|
|
use crate::thread::{self, ThreadId};
|
||
|
|
use crate::time::Duration;
|
||
|
|
|
||
|
|
// !!! These tests are dangerous. If something is buggy, they will hang, !!!
|
||
|
|
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_unnamed_thread() {
|
||
|
|
thread::spawn(move || {
|
||
|
|
assert!(thread::current().name().is_none());
|
||
|
|
})
|
||
|
|
.join()
|
||
|
|
.ok()
|
||
|
|
.expect("thread panicked");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_named_thread() {
|
||
|
|
Builder::new()
|
||
|
|
.name("ada lovelace".to_string())
|
||
|
|
.spawn(move || {
|
||
|
|
assert!(thread::current().name().unwrap() == "ada lovelace".to_string());
|
||
|
|
})
|
||
|
|
.unwrap()
|
||
|
|
.join()
|
||
|
|
.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
#[should_panic]
|
||
|
|
fn test_invalid_named_thread() {
|
||
|
|
let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {});
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_run_basic() {
|
||
|
|
let (tx, rx) = channel();
|
||
|
|
thread::spawn(move || {
|
||
|
|
tx.send(()).unwrap();
|
||
|
|
});
|
||
|
|
rx.recv().unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_join_panic() {
|
||
|
|
match thread::spawn(move || panic!()).join() {
|
||
|
|
result::Result::Err(_) => (),
|
||
|
|
result::Result::Ok(()) => panic!(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_spawn_sched() {
|
||
|
|
let (tx, rx) = channel();
|
||
|
|
|
||
|
|
fn f(i: i32, tx: Sender<()>) {
|
||
|
|
let tx = tx.clone();
|
||
|
|
thread::spawn(move || {
|
||
|
|
if i == 0 {
|
||
|
|
tx.send(()).unwrap();
|
||
|
|
} else {
|
||
|
|
f(i - 1, tx);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
f(10, tx);
|
||
|
|
rx.recv().unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_spawn_sched_childs_on_default_sched() {
|
||
|
|
let (tx, rx) = channel();
|
||
|
|
|
||
|
|
thread::spawn(move || {
|
||
|
|
thread::spawn(move || {
|
||
|
|
tx.send(()).unwrap();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
rx.recv().unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
fn avoid_copying_the_body<F>(spawnfn: F)
|
||
|
|
where
|
||
|
|
F: FnOnce(Box<dyn Fn() + Send>),
|
||
|
|
{
|
||
|
|
let (tx, rx) = channel();
|
||
|
|
|
||
|
|
let x: Box<_> = box 1;
|
||
|
|
let x_in_parent = (&*x) as *const i32 as usize;
|
||
|
|
|
||
|
|
spawnfn(Box::new(move || {
|
||
|
|
let x_in_child = (&*x) as *const i32 as usize;
|
||
|
|
tx.send(x_in_child).unwrap();
|
||
|
|
}));
|
||
|
|
|
||
|
|
let x_in_child = rx.recv().unwrap();
|
||
|
|
assert_eq!(x_in_parent, x_in_child);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_avoid_copying_the_body_spawn() {
|
||
|
|
avoid_copying_the_body(|v| {
|
||
|
|
thread::spawn(move || v());
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_avoid_copying_the_body_thread_spawn() {
|
||
|
|
avoid_copying_the_body(|f| {
|
||
|
|
thread::spawn(move || {
|
||
|
|
f();
|
||
|
|
});
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_avoid_copying_the_body_join() {
|
||
|
|
avoid_copying_the_body(|f| {
|
||
|
|
let _ = thread::spawn(move || f()).join();
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_child_doesnt_ref_parent() {
|
||
|
|
// If the child refcounts the parent thread, this will stack overflow when
|
||
|
|
// climbing the thread tree to dereference each ancestor. (See #1789)
|
||
|
|
// (well, it would if the constant were 8000+ - I lowered it to be more
|
||
|
|
// valgrind-friendly. try this at home, instead..!)
|
||
|
|
const GENERATIONS: u32 = 16;
|
||
|
|
fn child_no(x: u32) -> Box<dyn Fn() + Send> {
|
||
|
|
return Box::new(move || {
|
||
|
|
if x < GENERATIONS {
|
||
|
|
thread::spawn(move || child_no(x + 1)());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
thread::spawn(|| child_no(0)());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_simple_newsched_spawn() {
|
||
|
|
thread::spawn(move || {});
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_try_panic_message_static_str() {
|
||
|
|
match thread::spawn(move || {
|
||
|
|
panic!("static string");
|
||
|
|
})
|
||
|
|
.join()
|
||
|
|
{
|
||
|
|
Err(e) => {
|
||
|
|
type T = &'static str;
|
||
|
|
assert!(e.is::<T>());
|
||
|
|
assert_eq!(*e.downcast::<T>().unwrap(), "static string");
|
||
|
|
}
|
||
|
|
Ok(()) => panic!(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_try_panic_message_owned_str() {
|
||
|
|
match thread::spawn(move || {
|
||
|
|
panic!("owned string".to_string());
|
||
|
|
})
|
||
|
|
.join()
|
||
|
|
{
|
||
|
|
Err(e) => {
|
||
|
|
type T = String;
|
||
|
|
assert!(e.is::<T>());
|
||
|
|
assert_eq!(*e.downcast::<T>().unwrap(), "owned string".to_string());
|
||
|
|
}
|
||
|
|
Ok(()) => panic!(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_try_panic_message_any() {
|
||
|
|
match thread::spawn(move || {
|
||
|
|
panic!(box 413u16 as Box<dyn Any + Send>);
|
||
|
|
})
|
||
|
|
.join()
|
||
|
|
{
|
||
|
|
Err(e) => {
|
||
|
|
type T = Box<dyn Any + Send>;
|
||
|
|
assert!(e.is::<T>());
|
||
|
|
let any = e.downcast::<T>().unwrap();
|
||
|
|
assert!(any.is::<u16>());
|
||
|
|
assert_eq!(*any.downcast::<u16>().unwrap(), 413);
|
||
|
|
}
|
||
|
|
Ok(()) => panic!(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_try_panic_message_unit_struct() {
|
||
|
|
struct Juju;
|
||
|
|
|
||
|
|
match thread::spawn(move || panic!(Juju)).join() {
|
||
|
|
Err(ref e) if e.is::<Juju>() => {}
|
||
|
|
Err(_) | Ok(()) => panic!(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_park_timeout_unpark_before() {
|
||
|
|
for _ in 0..10 {
|
||
|
|
thread::current().unpark();
|
||
|
|
thread::park_timeout(Duration::from_millis(u32::MAX as u64));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_park_timeout_unpark_not_called() {
|
||
|
|
for _ in 0..10 {
|
||
|
|
thread::park_timeout(Duration::from_millis(10));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_park_timeout_unpark_called_other_thread() {
|
||
|
|
for _ in 0..10 {
|
||
|
|
let th = thread::current();
|
||
|
|
|
||
|
|
let _guard = thread::spawn(move || {
|
||
|
|
super::sleep(Duration::from_millis(50));
|
||
|
|
th.unpark();
|
||
|
|
});
|
||
|
|
|
||
|
|
thread::park_timeout(Duration::from_millis(u32::MAX as u64));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn sleep_ms_smoke() {
|
||
|
|
thread::sleep(Duration::from_millis(2));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_size_of_option_thread_id() {
|
||
|
|
assert_eq!(mem::size_of::<Option<ThreadId>>(), mem::size_of::<ThreadId>());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_thread_id_equal() {
|
||
|
|
assert!(thread::current().id() == thread::current().id());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn test_thread_id_not_equal() {
|
||
|
|
let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap();
|
||
|
|
assert!(thread::current().id() != spawned_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// NOTE: the corresponding test for stderr is in ui/thread-stderr, due
|
||
|
|
// to the test harness apparently interfering with stderr configuration.
|