about summary refs log tree commit diff
path: root/library/std/src/thread
diff options
context:
space:
mode:
authorLzu Tao <taolzu@gmail.com>2020-08-27 13:45:01 +0000
committerLzu Tao <taolzu@gmail.com>2020-08-31 02:56:59 +0000
commita4e926daeeaedc9178846711daf1f4cb6ce505fb (patch)
tree0c830f716f6f5ad17736d459f5de9b9199006d54 /library/std/src/thread
parentdb6cbfc49ca655739ba8caae43ebd7c77c8a1179 (diff)
downloadrust-a4e926daeeaedc9178846711daf1f4cb6ce505fb.tar.gz
rust-a4e926daeeaedc9178846711daf1f4cb6ce505fb.zip
std: move "mod tests/benches" to separate files
Also doing fmt inplace as requested.
Diffstat (limited to 'library/std/src/thread')
-rw-r--r--library/std/src/thread/local.rs206
-rw-r--r--library/std/src/thread/local/dynamic_tests.rs40
-rw-r--r--library/std/src/thread/local/tests.rs154
-rw-r--r--library/std/src/thread/mod.rs273
-rw-r--r--library/std/src/thread/tests.rs262
5 files changed, 465 insertions, 470 deletions
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index a4562967f0b..9d8c6f1815e 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -2,6 +2,12 @@
 
 #![unstable(feature = "thread_local_internals", issue = "none")]
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
+#[cfg(test)]
+mod dynamic_tests;
+
 use crate::error::Error;
 use crate::fmt;
 
@@ -547,203 +553,3 @@ pub mod os {
         key.os.set(ptr::null_mut());
     }
 }
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
-    use crate::cell::{Cell, UnsafeCell};
-    use crate::sync::mpsc::{channel, Sender};
-    use crate::thread;
-
-    struct Foo(Sender<()>);
-
-    impl Drop for Foo {
-        fn drop(&mut self) {
-            let Foo(ref s) = *self;
-            s.send(()).unwrap();
-        }
-    }
-
-    #[test]
-    fn smoke_no_dtor() {
-        thread_local!(static FOO: Cell<i32> = Cell::new(1));
-
-        FOO.with(|f| {
-            assert_eq!(f.get(), 1);
-            f.set(2);
-        });
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move || {
-            FOO.with(|f| {
-                assert_eq!(f.get(), 1);
-            });
-            tx.send(()).unwrap();
-        });
-        rx.recv().unwrap();
-
-        FOO.with(|f| {
-            assert_eq!(f.get(), 2);
-        });
-    }
-
-    #[test]
-    fn states() {
-        struct Foo;
-        impl Drop for Foo {
-            fn drop(&mut self) {
-                assert!(FOO.try_with(|_| ()).is_err());
-            }
-        }
-        thread_local!(static FOO: Foo = Foo);
-
-        thread::spawn(|| {
-            assert!(FOO.try_with(|_| ()).is_ok());
-        })
-        .join()
-        .ok()
-        .expect("thread panicked");
-    }
-
-    #[test]
-    fn smoke_dtor() {
-        thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
-
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move || unsafe {
-            let mut tx = Some(tx);
-            FOO.with(|f| {
-                *f.get() = Some(Foo(tx.take().unwrap()));
-            });
-        });
-        rx.recv().unwrap();
-    }
-
-    #[test]
-    fn circular() {
-        struct S1;
-        struct S2;
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
-        thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
-        static mut HITS: u32 = 0;
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                unsafe {
-                    HITS += 1;
-                    if K2.try_with(|_| ()).is_err() {
-                        assert_eq!(HITS, 3);
-                    } else {
-                        if HITS == 1 {
-                            K2.with(|s| *s.get() = Some(S2));
-                        } else {
-                            assert_eq!(HITS, 3);
-                        }
-                    }
-                }
-            }
-        }
-        impl Drop for S2 {
-            fn drop(&mut self) {
-                unsafe {
-                    HITS += 1;
-                    assert!(K1.try_with(|_| ()).is_ok());
-                    assert_eq!(HITS, 2);
-                    K1.with(|s| *s.get() = Some(S1));
-                }
-            }
-        }
-
-        thread::spawn(move || {
-            drop(S1);
-        })
-        .join()
-        .ok()
-        .expect("thread panicked");
-    }
-
-    #[test]
-    fn self_referential() {
-        struct S1;
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                assert!(K1.try_with(|_| ()).is_err());
-            }
-        }
-
-        thread::spawn(move || unsafe {
-            K1.with(|s| *s.get() = Some(S1));
-        })
-        .join()
-        .ok()
-        .expect("thread panicked");
-    }
-
-    // Note that this test will deadlock if TLS destructors aren't run (this
-    // requires the destructor to be run to pass the test).
-    #[test]
-    fn dtors_in_dtors_in_dtors() {
-        struct S1(Sender<()>);
-        thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
-        thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
-
-        impl Drop for S1 {
-            fn drop(&mut self) {
-                let S1(ref tx) = *self;
-                unsafe {
-                    let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
-                }
-            }
-        }
-
-        let (tx, rx) = channel();
-        let _t = thread::spawn(move || unsafe {
-            let mut tx = Some(tx);
-            K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
-        });
-        rx.recv().unwrap();
-    }
-}
-
-#[cfg(test)]
-mod dynamic_tests {
-    use crate::cell::RefCell;
-    use crate::collections::HashMap;
-
-    #[test]
-    fn smoke() {
-        fn square(i: i32) -> i32 {
-            i * i
-        }
-        thread_local!(static FOO: i32 = square(3));
-
-        FOO.with(|f| {
-            assert_eq!(*f, 9);
-        });
-    }
-
-    #[test]
-    fn hashmap() {
-        fn map() -> RefCell<HashMap<i32, i32>> {
-            let mut m = HashMap::new();
-            m.insert(1, 2);
-            RefCell::new(m)
-        }
-        thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
-
-        FOO.with(|map| {
-            assert_eq!(map.borrow()[&1], 2);
-        });
-    }
-
-    #[test]
-    fn refcell_vec() {
-        thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
-
-        FOO.with(|vec| {
-            assert_eq!(vec.borrow().len(), 3);
-            vec.borrow_mut().push(4);
-            assert_eq!(vec.borrow()[3], 4);
-        });
-    }
-}
diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/src/thread/local/dynamic_tests.rs
new file mode 100644
index 00000000000..dd180041648
--- /dev/null
+++ b/library/std/src/thread/local/dynamic_tests.rs
@@ -0,0 +1,40 @@
+use crate::cell::RefCell;
+use crate::collections::HashMap;
+use crate::thread_local;
+
+#[test]
+fn smoke() {
+    fn square(i: i32) -> i32 {
+        i * i
+    }
+    thread_local!(static FOO: i32 = square(3));
+
+    FOO.with(|f| {
+        assert_eq!(*f, 9);
+    });
+}
+
+#[test]
+fn hashmap() {
+    fn map() -> RefCell<HashMap<i32, i32>> {
+        let mut m = HashMap::new();
+        m.insert(1, 2);
+        RefCell::new(m)
+    }
+    thread_local!(static FOO: RefCell<HashMap<i32, i32>> = map());
+
+    FOO.with(|map| {
+        assert_eq!(map.borrow()[&1], 2);
+    });
+}
+
+#[test]
+fn refcell_vec() {
+    thread_local!(static FOO: RefCell<Vec<u32>> = RefCell::new(vec![1, 2, 3]));
+
+    FOO.with(|vec| {
+        assert_eq!(vec.borrow().len(), 3);
+        vec.borrow_mut().push(4);
+        assert_eq!(vec.borrow()[3], 4);
+    });
+}
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
new file mode 100644
index 00000000000..4fb0a089082
--- /dev/null
+++ b/library/std/src/thread/local/tests.rs
@@ -0,0 +1,154 @@
+use crate::cell::{Cell, UnsafeCell};
+use crate::sync::mpsc::{channel, Sender};
+use crate::thread;
+use crate::thread_local;
+
+struct Foo(Sender<()>);
+
+impl Drop for Foo {
+    fn drop(&mut self) {
+        let Foo(ref s) = *self;
+        s.send(()).unwrap();
+    }
+}
+
+#[test]
+fn smoke_no_dtor() {
+    thread_local!(static FOO: Cell<i32> = Cell::new(1));
+
+    FOO.with(|f| {
+        assert_eq!(f.get(), 1);
+        f.set(2);
+    });
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || {
+        FOO.with(|f| {
+            assert_eq!(f.get(), 1);
+        });
+        tx.send(()).unwrap();
+    });
+    rx.recv().unwrap();
+
+    FOO.with(|f| {
+        assert_eq!(f.get(), 2);
+    });
+}
+
+#[test]
+fn states() {
+    struct Foo;
+    impl Drop for Foo {
+        fn drop(&mut self) {
+            assert!(FOO.try_with(|_| ()).is_err());
+        }
+    }
+    thread_local!(static FOO: Foo = Foo);
+
+    thread::spawn(|| {
+        assert!(FOO.try_with(|_| ()).is_ok());
+    })
+    .join()
+    .ok()
+    .expect("thread panicked");
+}
+
+#[test]
+fn smoke_dtor() {
+    thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || unsafe {
+        let mut tx = Some(tx);
+        FOO.with(|f| {
+            *f.get() = Some(Foo(tx.take().unwrap()));
+        });
+    });
+    rx.recv().unwrap();
+}
+
+#[test]
+fn circular() {
+    struct S1;
+    struct S2;
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
+    static mut HITS: u32 = 0;
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            unsafe {
+                HITS += 1;
+                if K2.try_with(|_| ()).is_err() {
+                    assert_eq!(HITS, 3);
+                } else {
+                    if HITS == 1 {
+                        K2.with(|s| *s.get() = Some(S2));
+                    } else {
+                        assert_eq!(HITS, 3);
+                    }
+                }
+            }
+        }
+    }
+    impl Drop for S2 {
+        fn drop(&mut self) {
+            unsafe {
+                HITS += 1;
+                assert!(K1.try_with(|_| ()).is_ok());
+                assert_eq!(HITS, 2);
+                K1.with(|s| *s.get() = Some(S1));
+            }
+        }
+    }
+
+    thread::spawn(move || {
+        drop(S1);
+    })
+    .join()
+    .ok()
+    .expect("thread panicked");
+}
+
+#[test]
+fn self_referential() {
+    struct S1;
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            assert!(K1.try_with(|_| ()).is_err());
+        }
+    }
+
+    thread::spawn(move || unsafe {
+        K1.with(|s| *s.get() = Some(S1));
+    })
+    .join()
+    .ok()
+    .expect("thread panicked");
+}
+
+// Note that this test will deadlock if TLS destructors aren't run (this
+// requires the destructor to be run to pass the test).
+#[test]
+fn dtors_in_dtors_in_dtors() {
+    struct S1(Sender<()>);
+    thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+    thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
+
+    impl Drop for S1 {
+        fn drop(&mut self) {
+            let S1(ref tx) = *self;
+            unsafe {
+                let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
+            }
+        }
+    }
+
+    let (tx, rx) = channel();
+    let _t = thread::spawn(move || unsafe {
+        let mut tx = Some(tx);
+        K1.with(|s| *s.get() = Some(S1(tx.take().unwrap())));
+    });
+    rx.recv().unwrap();
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 0b9849517c2..6d6be8560aa 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -145,6 +145,9 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests;
+
 use crate::any::Any;
 use crate::cell::UnsafeCell;
 use crate::ffi::{CStr, CString};
@@ -1470,273 +1473,3 @@ fn _assert_sync_and_send() {
     _assert_both::<JoinHandle<()>>();
     _assert_both::<Thread>();
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// Tests
-////////////////////////////////////////////////////////////////////////////////
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod tests {
-    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.
-}
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
new file mode 100644
index 00000000000..16ad366fc12
--- /dev/null
+++ b/library/std/src/thread/tests.rs
@@ -0,0 +1,262 @@
+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.