diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
commit | 64d98f8ee037282c35007b64c2649055c56af1db (patch) | |
tree | 5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /tests/ui/threads-sendsync | |
parent | Adding debian version 1.67.1+dfsg1-1. (diff) | |
download | rustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/threads-sendsync')
68 files changed, 2211 insertions, 0 deletions
diff --git a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs new file mode 100644 index 000000000..4d3c4e8ac --- /dev/null +++ b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs @@ -0,0 +1,10 @@ +#![feature(cfg_target_thread_local, thread_local)] +#![crate_type = "lib"] + +#[cfg(target_thread_local)] +use std::cell::Cell; + +#[no_mangle] +#[cfg(target_thread_local)] +#[thread_local] +pub static FOO: Cell<u32> = Cell::new(3); diff --git a/tests/ui/threads-sendsync/child-outlives-parent.rs b/tests/ui/threads-sendsync/child-outlives-parent.rs new file mode 100644 index 000000000..e3a39a44b --- /dev/null +++ b/tests/ui/threads-sendsync/child-outlives-parent.rs @@ -0,0 +1,13 @@ +// run-pass +// Reported as issue #126, child leaks the string. + +// pretty-expanded FIXME #23616 +// ignore-emscripten no threads support + +use std::thread; + +fn child2(_s: String) { } + +pub fn main() { + let _x = thread::spawn(move|| child2("hi".to_string())); +} diff --git a/tests/ui/threads-sendsync/clone-with-exterior.rs b/tests/ui/threads-sendsync/clone-with-exterior.rs new file mode 100644 index 000000000..9fc661b14 --- /dev/null +++ b/tests/ui/threads-sendsync/clone-with-exterior.rs @@ -0,0 +1,20 @@ +// run-pass + +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +struct Pair { + a: isize, + b: isize +} + +pub fn main() { + let z: Box<_> = Box::new(Pair { a : 10, b : 12}); + + thread::spawn(move|| { + assert_eq!(z.a, 10); + assert_eq!(z.b, 12); + }).join(); +} diff --git a/tests/ui/threads-sendsync/comm.rs b/tests/ui/threads-sendsync/comm.rs new file mode 100644 index 000000000..aa86e174d --- /dev/null +++ b/tests/ui/threads-sendsync/comm.rs @@ -0,0 +1,22 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +pub fn main() { + let (tx, rx) = channel(); + let t = thread::spawn(move|| { child(&tx) }); + let y = rx.recv().unwrap(); + println!("received"); + println!("{}", y); + assert_eq!(y, 10); + t.join(); +} + +fn child(c: &Sender<isize>) { + println!("sending"); + c.send(10).unwrap(); + println!("value sent"); +} diff --git a/tests/ui/threads-sendsync/eprint-on-tls-drop.rs b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs new file mode 100644 index 000000000..f52430773 --- /dev/null +++ b/tests/ui/threads-sendsync/eprint-on-tls-drop.rs @@ -0,0 +1,49 @@ +// run-pass +// ignore-emscripten no processes +// ignore-sgx no processes + +use std::cell::RefCell; +use std::env; +use std::process::Command; + +fn main() { + let name = "YOU_ARE_THE_TEST"; + if env::var(name).is_ok() { + std::thread::spawn(|| { + TLS.with(|f| f.borrow().ensure()); + }) + .join() + .unwrap(); + } else { + let me = env::current_exe().unwrap(); + let output = Command::new(&me).env(name, "1").output().unwrap(); + println!("{:?}", output); + assert!(output.status.success()); + let stderr = String::from_utf8(output.stderr).unwrap(); + assert!(stderr.contains("hello new\n")); + assert!(stderr.contains("hello drop\n")); + } +} + +struct Stuff { + _x: usize, +} + +impl Stuff { + fn new() -> Self { + eprintln!("hello new"); + Self { _x: 0 } + } + + fn ensure(&self) {} +} + +impl Drop for Stuff { + fn drop(&mut self) { + eprintln!("hello drop"); + } +} + +thread_local! { + static TLS: RefCell<Stuff> = RefCell::new(Stuff::new()); +} diff --git a/tests/ui/threads-sendsync/issue-24313.rs b/tests/ui/threads-sendsync/issue-24313.rs new file mode 100644 index 000000000..c28b4ca96 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-24313.rs @@ -0,0 +1,32 @@ +// run-pass +// ignore-emscripten no threads +// ignore-sgx no processes + +use std::thread; +use std::env; +use std::process::Command; + +struct Handle(i32); + +impl Drop for Handle { + fn drop(&mut self) { panic!(); } +} + +thread_local!(static HANDLE: Handle = Handle(0)); + +fn main() { + let args = env::args().collect::<Vec<_>>(); + if args.len() == 1 { + let out = Command::new(&args[0]).arg("test").output().unwrap(); + let stderr = std::str::from_utf8(&out.stderr).unwrap(); + assert!(stderr.contains("panicked at 'explicit panic'"), + "bad failure message:\n{}\n", stderr); + } else { + // TLS dtors are not always run on process exit + thread::spawn(|| { + HANDLE.with(|h| { + println!("{}", h.0); + }); + }).join().unwrap(); + } +} diff --git a/tests/ui/threads-sendsync/issue-29488.rs b/tests/ui/threads-sendsync/issue-29488.rs new file mode 100644 index 000000000..3c9a6a80d --- /dev/null +++ b/tests/ui/threads-sendsync/issue-29488.rs @@ -0,0 +1,23 @@ +// run-pass +// ignore-emscripten no threads support + +use std::thread; + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + println!("test2"); + } +} + +thread_local!(static FOO: Foo = Foo); + +fn main() { + // Off the main thread due to #28129, be sure to initialize FOO first before + // calling `println!` + thread::spawn(|| { + FOO.with(|_| {}); + println!("test1"); + }).join().unwrap(); +} diff --git a/tests/ui/threads-sendsync/issue-43733-2.rs b/tests/ui/threads-sendsync/issue-43733-2.rs new file mode 100644 index 000000000..32baeec43 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-43733-2.rs @@ -0,0 +1,30 @@ +// ignore-wasm32 +// dont-check-compiler-stderr +#![feature(cfg_target_thread_local, thread_local_internals)] + +// On platforms *without* `#[thread_local]`, use +// a custom non-`Sync` type to fake the same error. +#[cfg(not(target_thread_local))] +struct Key<T> { + _data: std::cell::UnsafeCell<Option<T>>, + _flag: std::cell::Cell<()>, +} + +#[cfg(not(target_thread_local))] +impl<T> Key<T> { + const fn new() -> Self { + Key { + _data: std::cell::UnsafeCell::new(None), + _flag: std::cell::Cell::new(()), + } + } +} + +#[cfg(target_thread_local)] +use std::thread::__FastLocalKeyInner as Key; + +static __KEY: Key<()> = Key::new(); +//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads +//~| ERROR cannot be shared between threads safely [E0277] + +fn main() {} diff --git a/tests/ui/threads-sendsync/issue-43733.mir.stderr b/tests/ui/threads-sendsync/issue-43733.mir.stderr new file mode 100644 index 000000000..1e21a6b37 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-43733.mir.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/issue-43733.rs:21:5 + | +LL | __KEY.get(Default::default) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/issue-43733.rs:26:42 + | +LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/threads-sendsync/issue-43733.rs b/tests/ui/threads-sendsync/issue-43733.rs new file mode 100644 index 000000000..935e02944 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-43733.rs @@ -0,0 +1,38 @@ +// ignore-wasm32 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck +// normalize-stderr-test: "__FastLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get" +// normalize-stderr-test: "__OsLocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get" +#![feature(thread_local)] +#![feature(cfg_target_thread_local, thread_local_internals)] + +use std::cell::RefCell; + +type Foo = std::cell::RefCell<String>; + +#[cfg(target_thread_local)] +#[thread_local] +static __KEY: std::thread::__FastLocalKeyInner<Foo> = std::thread::__FastLocalKeyInner::new(); + +#[cfg(not(target_thread_local))] +static __KEY: std::thread::__OsLocalKeyInner<Foo> = std::thread::__OsLocalKeyInner::new(); + +fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> { + __KEY.get(Default::default) + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `__ +} + +static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit); +//[mir]~^ ERROR call to unsafe function is unsafe +//[thir]~^^ ERROR call to unsafe function `LocalKey::<T>::new` + +fn main() { + FOO.with(|foo| println!("{}", foo.borrow())); + std::thread::spawn(|| { + FOO.with(|foo| *foo.borrow_mut() += "foo"); + }) + .join() + .unwrap(); + FOO.with(|foo| println!("{}", foo.borrow())); +} diff --git a/tests/ui/threads-sendsync/issue-43733.thir.stderr b/tests/ui/threads-sendsync/issue-43733.thir.stderr new file mode 100644 index 000000000..ea7ff4080 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-43733.thir.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `$LOCALKEYINNER::<T>::get` is unsafe and requires unsafe function or block + --> $DIR/issue-43733.rs:21:5 + | +LL | __KEY.get(Default::default) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `LocalKey::<T>::new` is unsafe and requires unsafe function or block + --> $DIR/issue-43733.rs:26:42 + | +LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/threads-sendsync/issue-4446.rs b/tests/ui/threads-sendsync/issue-4446.rs new file mode 100644 index 000000000..948f2a7bd --- /dev/null +++ b/tests/ui/threads-sendsync/issue-4446.rs @@ -0,0 +1,15 @@ +// run-pass +// ignore-emscripten no threads support + +use std::sync::mpsc::channel; +use std::thread; + +pub fn main() { + let (tx, rx) = channel(); + + tx.send("hello, world").unwrap(); + + thread::spawn(move|| { + println!("{}", rx.recv().unwrap()); + }).join().ok().unwrap(); +} diff --git a/tests/ui/threads-sendsync/issue-4448.rs b/tests/ui/threads-sendsync/issue-4448.rs new file mode 100644 index 000000000..27d032689 --- /dev/null +++ b/tests/ui/threads-sendsync/issue-4448.rs @@ -0,0 +1,16 @@ +// run-pass +// ignore-emscripten no threads support + +use std::sync::mpsc::channel; +use std::thread; + +pub fn main() { + let (tx, rx) = channel::<&'static str>(); + + let t = thread::spawn(move|| { + assert_eq!(rx.recv().unwrap(), "hello, world"); + }); + + tx.send("hello, world").unwrap(); + t.join().ok().unwrap(); +} diff --git a/tests/ui/threads-sendsync/issue-8827.rs b/tests/ui/threads-sendsync/issue-8827.rs new file mode 100644 index 000000000..95be7616a --- /dev/null +++ b/tests/ui/threads-sendsync/issue-8827.rs @@ -0,0 +1,53 @@ +// run-pass +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Receiver}; + +fn periodical(n: isize) -> Receiver<bool> { + let (chan, port) = channel(); + thread::spawn(move|| { + loop { + for _ in 1..n { + match chan.send(false) { + Ok(()) => {} + Err(..) => break, + } + } + match chan.send(true) { + Ok(()) => {} + Err(..) => break + } + } + }); + return port; +} + +fn integers() -> Receiver<isize> { + let (chan, port) = channel(); + thread::spawn(move|| { + let mut i = 1; + loop { + match chan.send(i) { + Ok(()) => {} + Err(..) => break, + } + i = i + 1; + } + }); + return port; +} + +fn main() { + let ints = integers(); + let threes = periodical(3); + let fives = periodical(5); + for _ in 1..100 { + match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) { + (_, true, true) => println!("FizzBuzz"), + (_, true, false) => println!("Fizz"), + (_, false, true) => println!("Buzz"), + (i, false, false) => println!("{}", i) + } + } +} diff --git a/tests/ui/threads-sendsync/issue-9396.rs b/tests/ui/threads-sendsync/issue-9396.rs new file mode 100644 index 000000000..3e7e9a51c --- /dev/null +++ b/tests/ui/threads-sendsync/issue-9396.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(deprecated)] +// ignore-emscripten no threads support + +use std::sync::mpsc::{TryRecvError, channel}; +use std::thread; + +pub fn main() { + let (tx, rx) = channel(); + let t = thread::spawn(move||{ + thread::sleep_ms(10); + tx.send(()).unwrap(); + }); + loop { + match rx.try_recv() { + Ok(()) => break, + Err(TryRecvError::Empty) => {} + Err(TryRecvError::Disconnected) => unreachable!() + } + } + t.join(); +} diff --git a/tests/ui/threads-sendsync/mpsc_stress.rs b/tests/ui/threads-sendsync/mpsc_stress.rs new file mode 100644 index 000000000..c2e1912de --- /dev/null +++ b/tests/ui/threads-sendsync/mpsc_stress.rs @@ -0,0 +1,200 @@ +// run-pass +// compile-flags:--test +// ignore-emscripten + +use std::sync::mpsc::channel; +use std::sync::mpsc::TryRecvError; +use std::sync::mpsc::RecvError; +use std::sync::mpsc::RecvTimeoutError; +use std::sync::Arc; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use std::thread; +use std::time::Duration; + + +/// Simple thread synchronization utility +struct Barrier { + // Not using mutex/condvar for precision + shared: Arc<AtomicUsize>, + count: usize, +} + +impl Barrier { + fn new(count: usize) -> Vec<Barrier> { + let shared = Arc::new(AtomicUsize::new(0)); + (0..count).map(|_| Barrier { shared: shared.clone(), count: count }).collect() + } + + fn new2() -> (Barrier, Barrier) { + let mut v = Barrier::new(2); + (v.pop().unwrap(), v.pop().unwrap()) + } + + /// Returns when `count` threads enter `wait` + fn wait(self) { + self.shared.fetch_add(1, Ordering::SeqCst); + while self.shared.load(Ordering::SeqCst) != self.count { + #[cfg(target_env = "sgx")] + thread::yield_now(); + } + } +} + + +fn shared_close_sender_does_not_lose_messages_iter() { + let (tb, rb) = Barrier::new2(); + + let (tx, rx) = channel(); + let _ = tx.clone(); // convert to shared + + thread::spawn(move || { + tb.wait(); + thread::sleep(Duration::from_micros(1)); + tx.send(17).expect("send"); + drop(tx); + }); + + let i = rx.into_iter(); + rb.wait(); + // Make sure it doesn't return disconnected before returning an element + assert_eq!(vec![17], i.collect::<Vec<_>>()); +} + +#[test] +fn shared_close_sender_does_not_lose_messages() { + with_minimum_timer_resolution(|| { + for _ in 0..10000 { + shared_close_sender_does_not_lose_messages_iter(); + } + }); +} + + +// https://github.com/rust-lang/rust/issues/39364 +fn concurrent_recv_timeout_and_upgrade_iter() { + // 1 us + let sleep = Duration::new(0, 1_000); + + let (a, b) = Barrier::new2(); + let (tx, rx) = channel(); + let th = thread::spawn(move || { + a.wait(); + loop { + match rx.recv_timeout(sleep) { + Ok(_) => { + break; + }, + Err(_) => {}, + } + } + }); + b.wait(); + thread::sleep(sleep); + tx.clone().send(()).expect("send"); + th.join().unwrap(); +} + +#[test] +fn concurrent_recv_timeout_and_upgrade() { + with_minimum_timer_resolution(|| { + for _ in 0..10000 { + concurrent_recv_timeout_and_upgrade_iter(); + } + }); +} + + +fn concurrent_writes_iter() { + const THREADS: usize = 4; + const PER_THR: usize = 100; + + let mut bs = Barrier::new(THREADS + 1); + let (tx, rx) = channel(); + + let mut threads = Vec::new(); + for j in 0..THREADS { + let tx = tx.clone(); + let b = bs.pop().unwrap(); + threads.push(thread::spawn(move || { + b.wait(); + for i in 0..PER_THR { + tx.send(j * 1000 + i).expect("send"); + } + })); + } + + let b = bs.pop().unwrap(); + b.wait(); + + let mut v: Vec<_> = rx.iter().take(THREADS * PER_THR).collect(); + v.sort(); + + for j in 0..THREADS { + for i in 0..PER_THR { + assert_eq!(j * 1000 + i, v[j * PER_THR + i]); + } + } + + for t in threads { + t.join().unwrap(); + } + + let one_us = Duration::new(0, 1000); + + assert_eq!(TryRecvError::Empty, rx.try_recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Timeout, rx.recv_timeout(one_us).unwrap_err()); + + drop(tx); + + assert_eq!(RecvError, rx.recv().unwrap_err()); + assert_eq!(RecvTimeoutError::Disconnected, rx.recv_timeout(one_us).unwrap_err()); + assert_eq!(TryRecvError::Disconnected, rx.try_recv().unwrap_err()); +} + +#[test] +fn concurrent_writes() { + with_minimum_timer_resolution(|| { + for _ in 0..100 { + concurrent_writes_iter(); + } + }); +} + +#[cfg(windows)] +pub mod timeapi { + #![allow(non_snake_case)] + use std::ffi::c_uint; + + pub const TIMERR_NOERROR: c_uint = 0; + + #[link(name = "winmm")] + extern "system" { + pub fn timeBeginPeriod(uPeriod: c_uint) -> c_uint; + pub fn timeEndPeriod(uPeriod: c_uint) -> c_uint; + } +} + +/// Window's minimum sleep time can be as much as 16ms. +// This function evaluates the closure with this resolution +// set as low as possible. +/// +/// This takes the above test's duration from 10000*16/1000/60=2.67 minutes to ~16 seconds. +fn with_minimum_timer_resolution(f: impl Fn()) { + #[cfg(windows)] + unsafe { + let ret = timeapi::timeBeginPeriod(1); + assert_eq!(ret, timeapi::TIMERR_NOERROR); + + f(); + + let ret = timeapi::timeEndPeriod(1); + assert_eq!(ret, timeapi::TIMERR_NOERROR); + } + + #[cfg(not(windows))] + { + f(); + } +} diff --git a/tests/ui/threads-sendsync/send-is-not-static-par-for.rs b/tests/ui/threads-sendsync/send-is-not-static-par-for.rs new file mode 100644 index 000000000..dbe465551 --- /dev/null +++ b/tests/ui/threads-sendsync/send-is-not-static-par-for.rs @@ -0,0 +1,34 @@ +// run-pass +#![allow(unused_imports)] +use std::thread; +use std::sync::Mutex; + +fn par_for<I, F>(iter: I, f: F) + where I: Iterator, + I::Item: Send, + F: Fn(I::Item) + Sync +{ + for item in iter { + f(item) + } +} + +fn sum(x: &[i32]) { + let sum_lengths = Mutex::new(0); + par_for(x.windows(4), |x| { + *sum_lengths.lock().unwrap() += x.len() + }); + + assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4); +} + +fn main() { + let mut elements = [0; 20]; + + // iterators over references into this stack frame + par_for(elements.iter_mut().enumerate(), |(i, x)| { + *x = i as i32 + }); + + sum(&elements) +} diff --git a/tests/ui/threads-sendsync/send-resource.rs b/tests/ui/threads-sendsync/send-resource.rs new file mode 100644 index 000000000..023a84d6b --- /dev/null +++ b/tests/ui/threads-sendsync/send-resource.rs @@ -0,0 +1,39 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +// pretty-expanded FIXME #23616 +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::channel; + +struct test { + f: isize, +} + +impl Drop for test { + fn drop(&mut self) {} +} + +fn test(f: isize) -> test { + test { + f: f + } +} + +pub fn main() { + let (tx, rx) = channel(); + + let t = thread::spawn(move|| { + let (tx2, rx2) = channel(); + tx.send(tx2).unwrap(); + + let _r = rx2.recv().unwrap(); + }); + + rx.recv().unwrap().send(test(42)).unwrap(); + + t.join(); +} diff --git a/tests/ui/threads-sendsync/send-type-inference.rs b/tests/ui/threads-sendsync/send-type-inference.rs new file mode 100644 index 000000000..0d9af7512 --- /dev/null +++ b/tests/ui/threads-sendsync/send-type-inference.rs @@ -0,0 +1,19 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(dead_code)] +#![allow(unused_mut)] +// pretty-expanded FIXME #23616 + +use std::sync::mpsc::{channel, Sender}; + +// tests that ctrl's type gets inferred properly +struct Command<K, V> { + key: K, + val: V +} + +fn cache_server<K:Send+'static,V:Send+'static>(mut tx: Sender<Sender<Command<K, V>>>) { + let (tx1, _rx) = channel(); + tx.send(tx1); +} +pub fn main() { } diff --git a/tests/ui/threads-sendsync/send_str_hashmap.rs b/tests/ui/threads-sendsync/send_str_hashmap.rs new file mode 100644 index 000000000..7d4cca8ad --- /dev/null +++ b/tests/ui/threads-sendsync/send_str_hashmap.rs @@ -0,0 +1,53 @@ +// run-pass +use std::collections::HashMap; +use std::borrow::Cow; + +use std::borrow::Cow::Borrowed as B; +use std::borrow::Cow::Owned as O; + +type SendStr = Cow<'static, str>; + +fn main() { + let mut map: HashMap<SendStr, usize> = HashMap::new(); + assert!(map.insert(B("foo"), 42).is_none()); + assert!(map.insert(O("foo".to_string()), 42).is_some()); + assert!(map.insert(B("foo"), 42).is_some()); + assert!(map.insert(O("foo".to_string()), 42).is_some()); + + assert!(map.insert(B("foo"), 43).is_some()); + assert!(map.insert(O("foo".to_string()), 44).is_some()); + assert!(map.insert(B("foo"), 45).is_some()); + assert!(map.insert(O("foo".to_string()), 46).is_some()); + + let v = 46; + + assert_eq!(map.get(&O("foo".to_string())), Some(&v)); + assert_eq!(map.get(&B("foo")), Some(&v)); + + let (a, b, c, d) = (50, 51, 52, 53); + + assert!(map.insert(B("abc"), a).is_none()); + assert!(map.insert(O("bcd".to_string()), b).is_none()); + assert!(map.insert(B("cde"), c).is_none()); + assert!(map.insert(O("def".to_string()), d).is_none()); + + assert!(map.insert(B("abc"), a).is_some()); + assert!(map.insert(O("bcd".to_string()), b).is_some()); + assert!(map.insert(B("cde"), c).is_some()); + assert!(map.insert(O("def".to_string()), d).is_some()); + + assert!(map.insert(O("abc".to_string()), a).is_some()); + assert!(map.insert(B("bcd"), b).is_some()); + assert!(map.insert(O("cde".to_string()), c).is_some()); + assert!(map.insert(B("def"), d).is_some()); + + assert_eq!(map.get("abc"), Some(&a)); + assert_eq!(map.get("bcd"), Some(&b)); + assert_eq!(map.get("cde"), Some(&c)); + assert_eq!(map.get("def"), Some(&d)); + + assert_eq!(map.get(&B("abc")), Some(&a)); + assert_eq!(map.get(&B("bcd")), Some(&b)); + assert_eq!(map.get(&B("cde")), Some(&c)); + assert_eq!(map.get(&B("def")), Some(&d)); +} diff --git a/tests/ui/threads-sendsync/send_str_treemap.rs b/tests/ui/threads-sendsync/send_str_treemap.rs new file mode 100644 index 000000000..4d4631745 --- /dev/null +++ b/tests/ui/threads-sendsync/send_str_treemap.rs @@ -0,0 +1,58 @@ +// run-pass +use std::collections::BTreeMap; +use std::borrow::Cow; + +use std::borrow::Cow::{Owned as O, Borrowed as B}; + +type SendStr = Cow<'static, str>; + +fn main() { + let mut map: BTreeMap<SendStr, usize> = BTreeMap::new(); + assert!(map.insert(B("foo"), 42).is_none()); + assert!(map.insert(O("foo".to_string()), 42).is_some()); + assert!(map.insert(B("foo"), 42).is_some()); + assert!(map.insert(O("foo".to_string()), 42).is_some()); + + assert!(map.insert(B("foo"), 43).is_some()); + assert!(map.insert(O("foo".to_string()), 44).is_some()); + assert!(map.insert(B("foo"), 45).is_some()); + assert!(map.insert(O("foo".to_string()), 46).is_some()); + + let v = 46; + + assert_eq!(map.get(&O("foo".to_string())), Some(&v)); + assert_eq!(map.get(&B("foo")), Some(&v)); + + let (a, b, c, d) = (50, 51, 52, 53); + + assert!(map.insert(B("abc"), a).is_none()); + assert!(map.insert(O("bcd".to_string()), b).is_none()); + assert!(map.insert(B("cde"), c).is_none()); + assert!(map.insert(O("def".to_string()), d).is_none()); + + assert!(map.insert(B("abc"), a).is_some()); + assert!(map.insert(O("bcd".to_string()), b).is_some()); + assert!(map.insert(B("cde"), c).is_some()); + assert!(map.insert(O("def".to_string()), d).is_some()); + + assert!(map.insert(O("abc".to_string()), a).is_some()); + assert!(map.insert(B("bcd"), b).is_some()); + assert!(map.insert(O("cde".to_string()), c).is_some()); + assert!(map.insert(B("def"), d).is_some()); + + assert_eq!(map.get(&B("abc")), Some(&a)); + assert_eq!(map.get(&B("bcd")), Some(&b)); + assert_eq!(map.get(&B("cde")), Some(&c)); + assert_eq!(map.get(&B("def")), Some(&d)); + + assert_eq!(map.get(&O("abc".to_string())), Some(&a)); + assert_eq!(map.get(&O("bcd".to_string())), Some(&b)); + assert_eq!(map.get(&O("cde".to_string())), Some(&c)); + assert_eq!(map.get(&O("def".to_string())), Some(&d)); + + assert!(map.remove(&B("foo")).is_some()); + assert_eq!(map.into_iter().map(|(k, v)| format!("{}{}", k, v)) + .collect::<Vec<String>>() + .concat(), + "abc50bcd51cde52def53".to_string()); +} diff --git a/tests/ui/threads-sendsync/sendable-class.rs b/tests/ui/threads-sendsync/sendable-class.rs new file mode 100644 index 000000000..7facf245b --- /dev/null +++ b/tests/ui/threads-sendsync/sendable-class.rs @@ -0,0 +1,28 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(non_camel_case_types)] + +// Test that a class with only sendable fields can be sent + +// pretty-expanded FIXME #23616 + +use std::sync::mpsc::channel; + +struct foo { + i: isize, + j: char, +} + +fn foo(i:isize, j: char) -> foo { + foo { + i: i, + j: j + } +} + +pub fn main() { + let (tx, rx) = channel(); + tx.send(foo(42, 'c')); +} diff --git a/tests/ui/threads-sendsync/sendfn-is-a-block.rs b/tests/ui/threads-sendsync/sendfn-is-a-block.rs new file mode 100644 index 000000000..62807d894 --- /dev/null +++ b/tests/ui/threads-sendsync/sendfn-is-a-block.rs @@ -0,0 +1,11 @@ +// run-pass + + +fn test<F>(f: F) -> usize where F: FnOnce(usize) -> usize { + return f(22); +} + +pub fn main() { + let y = test(|x| 4 * x); + assert_eq!(y, 88); +} diff --git a/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs b/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs new file mode 100644 index 000000000..1e598b9e7 --- /dev/null +++ b/tests/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs @@ -0,0 +1,21 @@ +// run-pass +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { test05(); } + +fn test05_start<F:FnOnce(isize)>(f: F) { + f(22); +} + +fn test05() { + let three: Box<_> = Box::new(3); + let fn_to_send = move|n:isize| { + println!("{}", *three + n); // will copy x into the closure + assert_eq!(*three, 3); + }; + thread::spawn(move|| { + test05_start(fn_to_send); + }).join().ok().unwrap(); +} diff --git a/tests/ui/threads-sendsync/spawn-fn.rs b/tests/ui/threads-sendsync/spawn-fn.rs new file mode 100644 index 000000000..1243bb257 --- /dev/null +++ b/tests/ui/threads-sendsync/spawn-fn.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +fn x(s: String, n: isize) { + println!("{}", s); + println!("{}", n); +} + +pub fn main() { + let t1 = thread::spawn(|| x("hello from first spawned fn".to_string(), 65) ); + let t2 = thread::spawn(|| x("hello from second spawned fn".to_string(), 66) ); + let t3 = thread::spawn(|| x("hello from third spawned fn".to_string(), 67) ); + let mut i = 30; + while i > 0 { + i = i - 1; + println!("parent sleeping"); + thread::yield_now(); + } + t1.join(); + t2.join(); + t3.join(); +} diff --git a/tests/ui/threads-sendsync/spawn-types.rs b/tests/ui/threads-sendsync/spawn-types.rs new file mode 100644 index 000000000..1bead6e1b --- /dev/null +++ b/tests/ui/threads-sendsync/spawn-types.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten no threads support + +/* + Make sure we can spawn tasks that take different types of + parameters. This is based on a test case for #520 provided by Rob + Arnold. + */ + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +type ctx = Sender<isize>; + +fn iotask(_tx: &ctx, ip: String) { + assert_eq!(ip, "localhost".to_string()); +} + +pub fn main() { + let (tx, _rx) = channel::<isize>(); + let t = thread::spawn(move|| iotask(&tx, "localhost".to_string()) ); + t.join().ok().unwrap(); +} diff --git a/tests/ui/threads-sendsync/spawn.rs b/tests/ui/threads-sendsync/spawn.rs new file mode 100644 index 000000000..b1dcc9417 --- /dev/null +++ b/tests/ui/threads-sendsync/spawn.rs @@ -0,0 +1,10 @@ +// run-pass +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + thread::spawn(move|| child(10)).join().ok().unwrap(); +} + +fn child(i: isize) { println!("{}", i); assert_eq!(i, 10); } diff --git a/tests/ui/threads-sendsync/spawn2.rs b/tests/ui/threads-sendsync/spawn2.rs new file mode 100644 index 000000000..83e066aef --- /dev/null +++ b/tests/ui/threads-sendsync/spawn2.rs @@ -0,0 +1,31 @@ +// run-pass +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + let t = thread::spawn(move|| child((10, 20, 30, 40, 50, 60, 70, 80, 90)) ); + t.join().ok().unwrap(); // forget Err value, since it doesn't implement Debug +} + +fn child(args: (isize, isize, isize, isize, isize, isize, isize, isize, isize)) { + let (i1, i2, i3, i4, i5, i6, i7, i8, i9) = args; + println!("{}", i1); + println!("{}", i2); + println!("{}", i3); + println!("{}", i4); + println!("{}", i5); + println!("{}", i6); + println!("{}", i7); + println!("{}", i8); + println!("{}", i9); + assert_eq!(i1, 10); + assert_eq!(i2, 20); + assert_eq!(i3, 30); + assert_eq!(i4, 40); + assert_eq!(i5, 50); + assert_eq!(i6, 60); + assert_eq!(i7, 70); + assert_eq!(i8, 80); + assert_eq!(i9, 90); +} diff --git a/tests/ui/threads-sendsync/spawning-with-debug.rs b/tests/ui/threads-sendsync/spawning-with-debug.rs new file mode 100644 index 000000000..9d3487ffb --- /dev/null +++ b/tests/ui/threads-sendsync/spawning-with-debug.rs @@ -0,0 +1,15 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(unused_mut)] +// ignore-windows +// exec-env:RUST_LOG=debug +// ignore-emscripten no threads support + +// regression test for issue #10405, make sure we don't call println! too soon. + +use std::thread::Builder; + +pub fn main() { + let mut t = Builder::new(); + t.spawn(move || ()); +} diff --git a/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs new file mode 100644 index 000000000..bc64c8162 --- /dev/null +++ b/tests/ui/threads-sendsync/std-sync-right-kind-impls.rs @@ -0,0 +1,16 @@ +// run-pass +// pretty-expanded FIXME #23616 + +use std::sync; + +fn assert_both<T: Sync + Send>() {} + +fn main() { + assert_both::<sync::Mutex<()>>(); + assert_both::<sync::Condvar>(); + assert_both::<sync::RwLock<()>>(); + assert_both::<sync::Barrier>(); + assert_both::<sync::Arc<()>>(); + assert_both::<sync::Weak<()>>(); + assert_both::<sync::Once>(); +} diff --git a/tests/ui/threads-sendsync/sync-send-atomics.rs b/tests/ui/threads-sendsync/sync-send-atomics.rs new file mode 100644 index 000000000..0466f4f0e --- /dev/null +++ b/tests/ui/threads-sendsync/sync-send-atomics.rs @@ -0,0 +1,14 @@ +// run-pass + +// pretty-expanded FIXME #23616 + +use std::sync::atomic::*; + +trait SendSync: Send + Sync {} + +impl SendSync for AtomicBool {} +impl SendSync for AtomicIsize {} +impl SendSync for AtomicUsize {} +impl<T> SendSync for AtomicPtr<T> {} + +fn main() {} diff --git a/tests/ui/threads-sendsync/sync-send-in-std.rs b/tests/ui/threads-sendsync/sync-send-in-std.rs new file mode 100644 index 000000000..6d1fba64e --- /dev/null +++ b/tests/ui/threads-sendsync/sync-send-in-std.rs @@ -0,0 +1,25 @@ +// run-pass + +// ignore-wasm32-bare networking not available +// ignore-sgx ToSocketAddrs cannot be used for DNS Resolution +// ignore-fuchsia Req. test-harness networking privileges + +use std::net::ToSocketAddrs; + +fn is_sync<T>(_: T) where T: Sync {} +fn is_send<T>(_: T) where T: Send {} + +macro_rules! all_sync_send { + ($ctor:expr, $($iter:ident),+) => ({ + $( + let mut x = $ctor; + is_sync(x.$iter()); + let mut y = $ctor; + is_send(y.$iter()); + )+ + }) +} + +fn main() { + all_sync_send!("localhost:80".to_socket_addrs().unwrap(), next); +} diff --git a/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs b/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs new file mode 100644 index 000000000..fd53bb607 --- /dev/null +++ b/tests/ui/threads-sendsync/sync-send-iterators-in-libcollections.rs @@ -0,0 +1,71 @@ +// run-pass + +#![allow(warnings)] +#![feature(drain, collections_bound, btree_range)] + +use std::collections::BinaryHeap; +use std::collections::{BTreeMap, BTreeSet}; +use std::collections::LinkedList; +use std::collections::VecDeque; +use std::collections::HashMap; +use std::collections::HashSet; + +use std::mem; +use std::ops::Bound::Included; + +fn is_sync<T>(_: T) where T: Sync {} +fn is_send<T>(_: T) where T: Send {} + +macro_rules! all_sync_send { + ($ctor:expr, $($iter:ident),+) => ({ + $( + let mut x = $ctor; + is_sync(x.$iter()); + let mut y = $ctor; + is_send(y.$iter()); + )+ + }) +} + +macro_rules! is_sync_send { + ($ctor:expr, $iter:ident($($param:expr),+)) => ({ + let mut x = $ctor; + is_sync(x.$iter($( $param ),+)); + let mut y = $ctor; + is_send(y.$iter($( $param ),+)); + }) +} + +fn main() { + // The iterator "generator" list should exhaust what corresponding + // implementations have where `Sync` and `Send` semantics apply. + all_sync_send!(BinaryHeap::<usize>::new(), iter, drain, into_iter); + + all_sync_send!(BTreeMap::<usize, usize>::new(), iter, iter_mut, into_iter, keys, values); + is_sync_send!(BTreeMap::<usize, usize>::new(), range((Included(&0), Included(&9)))); + is_sync_send!(BTreeMap::<usize, usize>::new(), range_mut((Included(&0), Included(&9)))); + + all_sync_send!(BTreeSet::<usize>::new(), iter, into_iter); + is_sync_send!(BTreeSet::<usize>::new(), range((Included(&0), Included(&9)))); + is_sync_send!(BTreeSet::<usize>::new(), difference(&BTreeSet::<usize>::new())); + is_sync_send!(BTreeSet::<usize>::new(), symmetric_difference(&BTreeSet::<usize>::new())); + is_sync_send!(BTreeSet::<usize>::new(), intersection(&BTreeSet::<usize>::new())); + is_sync_send!(BTreeSet::<usize>::new(), union(&BTreeSet::<usize>::new())); + + all_sync_send!(HashMap::<usize, usize>::new(), iter, iter_mut, drain, into_iter, keys, values); + is_sync_send!(HashMap::<usize, usize>::new(), entry(0)); + all_sync_send!(HashSet::<usize>::new(), iter, drain, into_iter); + is_sync_send!(HashSet::<usize>::new(), difference(&HashSet::<usize>::new())); + is_sync_send!(HashSet::<usize>::new(), symmetric_difference(&HashSet::<usize>::new())); + is_sync_send!(HashSet::<usize>::new(), intersection(&HashSet::<usize>::new())); + is_sync_send!(HashSet::<usize>::new(), union(&HashSet::<usize>::new())); + + all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter); + + all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter); + is_sync_send!(VecDeque::<usize>::new(), drain(..)); + + all_sync_send!(Vec::<usize>::new(), into_iter); + is_sync_send!(Vec::<usize>::new(), drain(..)); + is_sync_send!(String::new(), drain(..)); +} diff --git a/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs b/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs new file mode 100644 index 000000000..2f6d35f01 --- /dev/null +++ b/tests/ui/threads-sendsync/sync-send-iterators-in-libcore.rs @@ -0,0 +1,105 @@ +// run-pass +// pretty-expanded FIXME #23616 + +#![allow(warnings)] + +use std::iter::{empty, once, repeat}; + +fn is_sync<T>(_: T) where T: Sync {} +fn is_send<T>(_: T) where T: Send {} + +macro_rules! all_sync_send { + ($ctor:expr, $iter:ident) => ({ + let mut x = $ctor; + is_sync(x.$iter()); + let mut y = $ctor; + is_send(y.$iter()); + }); + ($ctor:expr, $iter:ident($($param:expr),+)) => ({ + let mut x = $ctor; + is_sync(x.$iter($( $param ),+)); + let mut y = $ctor; + is_send(y.$iter($( $param ),+)); + }); + ($ctor:expr, $iter:ident, $($rest:tt)*) => ({ + all_sync_send!($ctor, $iter); + all_sync_send!($ctor, $($rest)*); + }); + ($ctor:expr, $iter:ident($($param:expr),+), $($rest:tt)*) => ({ + all_sync_send!($ctor, $iter($( $param ),+)); + all_sync_send!($ctor, $($rest)*); + }); +} + +macro_rules! all_sync_send_mutable_ref { + ($ctor:expr, $($iter:ident),+) => ({ + $( + let mut x = $ctor; + is_sync((&mut x).$iter()); + let mut y = $ctor; + is_send((&mut y).$iter()); + )+ + }) +} + +macro_rules! is_sync_send { + ($ctor:expr) => ({ + let x = $ctor; + is_sync(x); + let y = $ctor; + is_send(y); + }) +} + +fn main() { + // for char.rs + all_sync_send!("Я", escape_debug, escape_default, escape_unicode); + + // for iter.rs + all_sync_send_mutable_ref!([1], iter); + + // Bytes implements DoubleEndedIterator + all_sync_send!("a".bytes(), rev); + + let a = [1]; + let b = [2]; + all_sync_send!(a.iter(), + cloned, + cycle, + chain([2].iter()), + zip([2].iter()), + map(|_| 1), + filter(|_| true), + filter_map(|_| Some(1)), + enumerate, + peekable, + skip_while(|_| true), + take_while(|_| true), + skip(1), + take(1), + scan(1, |_, _| Some(1)), + flat_map(|_| b.iter()), + fuse, + inspect(|_| ())); + + is_sync_send!((1..).step_by(2)); + is_sync_send!((1..2).step_by(2)); + is_sync_send!((1..2)); + is_sync_send!((1..)); + is_sync_send!(repeat(1)); + is_sync_send!(empty::<usize>()); + is_sync_send!(empty::<*mut i32>()); + is_sync_send!(once(1)); + + // for option.rs + // FIXME + + // for result.rs + // FIXME + + // for slice.rs + // FIXME + + // for str/mod.rs + // FIXME +} diff --git a/tests/ui/threads-sendsync/task-comm-0.rs b/tests/ui/threads-sendsync/task-comm-0.rs new file mode 100644 index 000000000..2b9a50e4d --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-0.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +pub fn main() { test05(); } + +fn test05_start(tx : &Sender<isize>) { + tx.send(10).unwrap(); + println!("sent 10"); + tx.send(20).unwrap(); + println!("sent 20"); + tx.send(30).unwrap(); + println!("sent 30"); +} + +fn test05() { + let (tx, rx) = channel(); + let t = thread::spawn(move|| { test05_start(&tx) }); + let mut value: isize = rx.recv().unwrap(); + println!("{}", value); + value = rx.recv().unwrap(); + println!("{}", value); + value = rx.recv().unwrap(); + println!("{}", value); + assert_eq!(value, 30); + t.join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-1.rs b/tests/ui/threads-sendsync/task-comm-1.rs new file mode 100644 index 000000000..68ca62909 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-1.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { test00(); } + +fn start() { println!("Started / Finished task."); } + +fn test00() { + thread::spawn(move|| start() ).join(); + println!("Completing."); +} diff --git a/tests/ui/threads-sendsync/task-comm-10.rs b/tests/ui/threads-sendsync/task-comm-10.rs new file mode 100644 index 000000000..4cac0dc90 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-10.rs @@ -0,0 +1,33 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(unused_mut)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +fn start(tx: &Sender<Sender<String>>) { + let (tx2, rx) = channel(); + tx.send(tx2).unwrap(); + + let mut a; + let mut b; + a = rx.recv().unwrap(); + assert_eq!(a, "A".to_string()); + println!("{}", a); + b = rx.recv().unwrap(); + assert_eq!(b, "B".to_string()); + println!("{}", b); +} + +pub fn main() { + let (tx, rx) = channel(); + let child = thread::spawn(move|| { start(&tx) }); + + let mut c = rx.recv().unwrap(); + c.send("A".to_string()).unwrap(); + c.send("B".to_string()).unwrap(); + thread::yield_now(); + + child.join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-11.rs b/tests/ui/threads-sendsync/task-comm-11.rs new file mode 100644 index 000000000..8541e143f --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-11.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(unused_must_use)] +// pretty-expanded FIXME #23616 +// ignore-emscripten no threads support + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +fn start(tx: &Sender<Sender<isize>>) { + let (tx2, _rx) = channel(); + tx.send(tx2).unwrap(); +} + +pub fn main() { + let (tx, rx) = channel(); + let child = thread::spawn(move|| { + start(&tx) + }); + let _tx = rx.recv().unwrap(); + child.join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-12.rs b/tests/ui/threads-sendsync/task-comm-12.rs new file mode 100644 index 000000000..613a5cee5 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-12.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(unused_mut)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { test00(); } + +fn start(_task_number: isize) { println!("Started / Finished task."); } + +fn test00() { + let i: isize = 0; + let mut result = thread::spawn(move|| { + start(i) + }); + + // Sleep long enough for the thread to finish. + let mut i = 0_usize; + while i < 10000 { + thread::yield_now(); + i += 1; + } + + // Try joining threads that have already finished. + result.join(); + + println!("Joined task."); +} diff --git a/tests/ui/threads-sendsync/task-comm-13.rs b/tests/ui/threads-sendsync/task-comm-13.rs new file mode 100644 index 000000000..327eaaf8f --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-13.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(unused_variables)] +// ignore-emscripten no threads support + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +fn start(tx: &Sender<isize>, start: isize, number_of_messages: isize) { + let mut i: isize = 0; + while i< number_of_messages { tx.send(start + i).unwrap(); i += 1; } +} + +pub fn main() { + println!("Check that we don't deadlock."); + let (tx, rx) = channel(); + let _ = thread::spawn(move|| { start(&tx, 0, 10) }).join(); + println!("Joined task"); +} diff --git a/tests/ui/threads-sendsync/task-comm-14.rs b/tests/ui/threads-sendsync/task-comm-14.rs new file mode 100644 index 000000000..88d6b0902 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-14.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(unused_parens)] +// ignore-emscripten no threads support + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +pub fn main() { + let (tx, rx) = channel(); + + // Spawn 10 threads each sending us back one isize. + let mut i = 10; + while (i > 0) { + println!("{}", i); + let tx = tx.clone(); + thread::spawn({let i = i; move|| { child(i, &tx) }}); + i = i - 1; + } + + // Spawned threads are likely killed before they get a chance to send + // anything back, so we deadlock here. + + i = 10; + while (i > 0) { + println!("{}", i); + rx.recv().unwrap(); + i = i - 1; + } + + println!("main thread exiting"); +} + +fn child(x: isize, tx: &Sender<isize>) { + println!("{}", x); + tx.send(x).unwrap(); +} diff --git a/tests/ui/threads-sendsync/task-comm-15.rs b/tests/ui/threads-sendsync/task-comm-15.rs new file mode 100644 index 000000000..adb14abdc --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-15.rs @@ -0,0 +1,28 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support +// pretty-expanded FIXME #23616 + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +fn start(tx: &Sender<isize>, i0: isize) { + let mut i = i0; + while i > 0 { + tx.send(0).unwrap(); + i = i - 1; + } +} + +pub fn main() { + // Spawn a thread that sends us back messages. The parent thread + // is likely to terminate before the child completes, so from + // the child's point of view the receiver may die. We should + // drop messages on the floor in this case, and not crash! + let (tx, rx) = channel(); + let t = thread::spawn(move|| { + start(&tx, 10) + }); + rx.recv(); + t.join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-16.rs b/tests/ui/threads-sendsync/task-comm-16.rs new file mode 100644 index 000000000..d808fd9ac --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-16.rs @@ -0,0 +1,111 @@ +// run-pass +#![allow(unused_mut)] +#![allow(unused_parens)] +#![allow(non_camel_case_types)] + +use std::sync::mpsc::channel; +use std::cmp; + +// Tests of ports and channels on various types +fn test_rec() { + struct R {val0: isize, val1: u8, val2: char} + + let (tx, rx) = channel(); + let r0: R = R {val0: 0, val1: 1, val2: '2'}; + tx.send(r0).unwrap(); + let mut r1: R; + r1 = rx.recv().unwrap(); + assert_eq!(r1.val0, 0); + assert_eq!(r1.val1, 1); + assert_eq!(r1.val2, '2'); +} + +fn test_vec() { + let (tx, rx) = channel(); + let v0: Vec<isize> = vec![0, 1, 2]; + tx.send(v0).unwrap(); + let v1 = rx.recv().unwrap(); + assert_eq!(v1[0], 0); + assert_eq!(v1[1], 1); + assert_eq!(v1[2], 2); +} + +fn test_str() { + let (tx, rx) = channel(); + let s0 = "test".to_string(); + tx.send(s0).unwrap(); + let s1 = rx.recv().unwrap(); + assert_eq!(s1.as_bytes()[0], 't' as u8); + assert_eq!(s1.as_bytes()[1], 'e' as u8); + assert_eq!(s1.as_bytes()[2], 's' as u8); + assert_eq!(s1.as_bytes()[3], 't' as u8); +} + +#[derive(Debug)] +enum t { + tag1, + tag2(isize), + tag3(isize, u8, char) +} + +impl cmp::PartialEq for t { + fn eq(&self, other: &t) -> bool { + match *self { + t::tag1 => { + match (*other) { + t::tag1 => true, + _ => false + } + } + t::tag2(e0a) => { + match (*other) { + t::tag2(e0b) => e0a == e0b, + _ => false + } + } + t::tag3(e0a, e1a, e2a) => { + match (*other) { + t::tag3(e0b, e1b, e2b) => + e0a == e0b && e1a == e1b && e2a == e2b, + _ => false + } + } + } + } + fn ne(&self, other: &t) -> bool { !(*self).eq(other) } +} + +fn test_tag() { + let (tx, rx) = channel(); + tx.send(t::tag1).unwrap(); + tx.send(t::tag2(10)).unwrap(); + tx.send(t::tag3(10, 11, 'A')).unwrap(); + let mut t1: t; + t1 = rx.recv().unwrap(); + assert_eq!(t1, t::tag1); + t1 = rx.recv().unwrap(); + assert_eq!(t1, t::tag2(10)); + t1 = rx.recv().unwrap(); + assert_eq!(t1, t::tag3(10, 11, 'A')); +} + +fn test_chan() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + tx1.send(tx2).unwrap(); + let tx2 = rx1.recv().unwrap(); + // Does the transmitted channel still work? + + tx2.send(10).unwrap(); + let mut i: isize; + i = rx2.recv().unwrap(); + assert_eq!(i, 10); +} + +pub fn main() { + test_rec(); + test_vec(); + test_str(); + test_tag(); + test_chan(); +} diff --git a/tests/ui/threads-sendsync/task-comm-17.rs b/tests/ui/threads-sendsync/task-comm-17.rs new file mode 100644 index 000000000..722497870 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-17.rs @@ -0,0 +1,17 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support +// pretty-expanded FIXME #23616 + +// Issue #922 + +// This test is specifically about spawning temporary closures. + +use std::thread; + +fn f() { +} + +pub fn main() { + thread::spawn(move|| f() ).join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-3.rs b/tests/ui/threads-sendsync/task-comm-3.rs new file mode 100644 index 000000000..570ae0a82 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-3.rs @@ -0,0 +1,63 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +pub fn main() { println!("===== WITHOUT THREADS ====="); test00(); } + +fn test00_start(ch: &Sender<isize>, message: isize, count: isize) { + println!("Starting test00_start"); + let mut i: isize = 0; + while i < count { + println!("Sending Message"); + ch.send(message + 0).unwrap(); + i = i + 1; + } + println!("Ending test00_start"); +} + +fn test00() { + let number_of_tasks: isize = 16; + let number_of_messages: isize = 4; + + println!("Creating tasks"); + + let (tx, rx) = channel(); + + let mut i: isize = 0; + + // Create and spawn threads... + let mut results = Vec::new(); + while i < number_of_tasks { + let tx = tx.clone(); + results.push(thread::spawn({ + let i = i; + move|| { + test00_start(&tx, i, number_of_messages) + } + })); + i = i + 1; + } + + // Read from spawned threads... + let mut sum = 0; + for _r in &results { + i = 0; + while i < number_of_messages { + let value = rx.recv().unwrap(); + sum += value; + i = i + 1; + } + } + + // Join spawned threads... + for r in results { r.join(); } + + println!("Completed: Final number is: "); + println!("{}", sum); + // assert (sum == (((number_of_threads * (number_of_threads - 1)) / 2) * + // number_of_messages)); + assert_eq!(sum, 480); +} diff --git a/tests/ui/threads-sendsync/task-comm-4.rs b/tests/ui/threads-sendsync/task-comm-4.rs new file mode 100644 index 000000000..b259d69d1 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-4.rs @@ -0,0 +1,45 @@ +// run-pass +#![allow(unused_assignments)] + +use std::sync::mpsc::channel; + +pub fn main() { test00(); } + +fn test00() { + let mut r: isize = 0; + let mut sum: isize = 0; + let (tx, rx) = channel(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + tx.send(3).unwrap(); + tx.send(4).unwrap(); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + tx.send(5).unwrap(); + tx.send(6).unwrap(); + tx.send(7).unwrap(); + tx.send(8).unwrap(); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + r = rx.recv().unwrap(); + sum += r; + println!("{}", r); + assert_eq!(sum, 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8); +} diff --git a/tests/ui/threads-sendsync/task-comm-5.rs b/tests/ui/threads-sendsync/task-comm-5.rs new file mode 100644 index 000000000..cdedf034a --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-5.rs @@ -0,0 +1,17 @@ +// run-pass + +use std::sync::mpsc::channel; + +pub fn main() { test00(); } + +fn test00() { + let _r: isize = 0; + let mut sum: isize = 0; + let (tx, rx) = channel(); + let number_of_messages: isize = 1000; + let mut i: isize = 0; + while i < number_of_messages { tx.send(i + 0).unwrap(); i += 1; } + i = 0; + while i < number_of_messages { sum += rx.recv().unwrap(); i += 1; } + assert_eq!(sum, number_of_messages * (number_of_messages - 1) / 2); +} diff --git a/tests/ui/threads-sendsync/task-comm-6.rs b/tests/ui/threads-sendsync/task-comm-6.rs new file mode 100644 index 000000000..990205ad3 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-6.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(unused_mut)] +#![allow(unused_assignments)] + +use std::sync::mpsc::channel; + +pub fn main() { test00(); } + +fn test00() { + let mut r: isize = 0; + let mut sum: isize = 0; + let (tx, rx) = channel(); + let mut tx0 = tx.clone(); + let mut tx1 = tx.clone(); + let mut tx2 = tx.clone(); + let mut tx3 = tx.clone(); + let number_of_messages: isize = 1000; + let mut i: isize = 0; + while i < number_of_messages { + tx0.send(i + 0).unwrap(); + tx1.send(i + 0).unwrap(); + tx2.send(i + 0).unwrap(); + tx3.send(i + 0).unwrap(); + i += 1; + } + i = 0; + while i < number_of_messages { + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + i += 1; + } + assert_eq!(sum, 1998000); + // assert (sum == 4 * ((number_of_messages * + // (number_of_messages - 1)) / 2)); + +} diff --git a/tests/ui/threads-sendsync/task-comm-7.rs b/tests/ui/threads-sendsync/task-comm-7.rs new file mode 100644 index 000000000..0b9673e00 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-7.rs @@ -0,0 +1,59 @@ +// run-pass +#![allow(unused_must_use)] +#![allow(unused_assignments)] +// ignore-emscripten no threads support + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +pub fn main() { test00(); } + +fn test00_start(c: &Sender<isize>, start: isize, + number_of_messages: isize) { + let mut i: isize = 0; + while i < number_of_messages { c.send(start + i).unwrap(); i += 1; } +} + +fn test00() { + let mut r: isize = 0; + let mut sum: isize = 0; + let (tx, rx) = channel(); + let number_of_messages: isize = 10; + + let tx2 = tx.clone(); + let t1 = thread::spawn(move|| { + test00_start(&tx2, number_of_messages * 0, number_of_messages); + }); + let tx2 = tx.clone(); + let t2 = thread::spawn(move|| { + test00_start(&tx2, number_of_messages * 1, number_of_messages); + }); + let tx2 = tx.clone(); + let t3 = thread::spawn(move|| { + test00_start(&tx2, number_of_messages * 2, number_of_messages); + }); + let tx2 = tx.clone(); + let t4 = thread::spawn(move|| { + test00_start(&tx2, number_of_messages * 3, number_of_messages); + }); + + let mut i: isize = 0; + while i < number_of_messages { + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + r = rx.recv().unwrap(); + sum += r; + i += 1; + } + + assert_eq!(sum, number_of_messages * 4 * (number_of_messages * 4 - 1) / 2); + + t1.join(); + t2.join(); + t3.join(); + t4.join(); +} diff --git a/tests/ui/threads-sendsync/task-comm-9.rs b/tests/ui/threads-sendsync/task-comm-9.rs new file mode 100644 index 000000000..5ed330121 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-9.rs @@ -0,0 +1,35 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::{channel, Sender}; + +pub fn main() { test00(); } + +fn test00_start(c: &Sender<isize>, number_of_messages: isize) { + let mut i: isize = 0; + while i < number_of_messages { c.send(i + 0).unwrap(); i += 1; } +} + +fn test00() { + let r: isize = 0; + let mut sum: isize = 0; + let (tx, rx) = channel(); + let number_of_messages: isize = 10; + + let result = thread::spawn(move|| { + test00_start(&tx, number_of_messages); + }); + + let mut i: isize = 0; + while i < number_of_messages { + sum += rx.recv().unwrap(); + println!("{}", r); + i += 1; + } + + result.join(); + + assert_eq!(sum, number_of_messages * (number_of_messages - 1) / 2); +} diff --git a/tests/ui/threads-sendsync/task-comm-chan-nil.rs b/tests/ui/threads-sendsync/task-comm-chan-nil.rs new file mode 100644 index 000000000..a93ddff43 --- /dev/null +++ b/tests/ui/threads-sendsync/task-comm-chan-nil.rs @@ -0,0 +1,13 @@ +// run-pass + +use std::sync::mpsc::channel; + +// rustboot can't transmit nils across channels because they don't have +// any size, but rustc currently can because they do have size. Whether +// or not this is desirable I don't know, but here's a regression test. +pub fn main() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + let n: () = rx.recv().unwrap(); + assert_eq!(n, ()); +} diff --git a/tests/ui/threads-sendsync/task-life-0.rs b/tests/ui/threads-sendsync/task-life-0.rs new file mode 100644 index 000000000..785cff9a0 --- /dev/null +++ b/tests/ui/threads-sendsync/task-life-0.rs @@ -0,0 +1,14 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support +// pretty-expanded FIXME #23616 + +use std::thread; + +pub fn main() { + thread::spawn(move|| child("Hello".to_string()) ).join(); +} + +fn child(_s: String) { + +} diff --git a/tests/ui/threads-sendsync/task-spawn-barefn.rs b/tests/ui/threads-sendsync/task-spawn-barefn.rs new file mode 100644 index 000000000..e5b899e0a --- /dev/null +++ b/tests/ui/threads-sendsync/task-spawn-barefn.rs @@ -0,0 +1,18 @@ +// run-fail +// error-pattern:Ensure that the child thread runs by panicking +// ignore-emscripten Needs threads. + +use std::thread; + +fn main() { + // the purpose of this test is to make sure that thread::spawn() + // works when provided with a bare function: + let r = thread::spawn(startfn).join(); + if r.is_err() { + panic!() + } +} + +fn startfn() { + assert!("Ensure that the child thread runs by panicking".is_empty()); +} diff --git a/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs b/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs new file mode 100644 index 000000000..a63903778 --- /dev/null +++ b/tests/ui/threads-sendsync/task-spawn-move-and-copy.rs @@ -0,0 +1,23 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; +use std::sync::mpsc::channel; + +pub fn main() { + let (tx, rx) = channel::<usize>(); + + let x: Box<isize> = Box::new(1); + let x_in_parent = &(*x) as *const isize as usize; + + let t = thread::spawn(move || { + let x_in_child = &(*x) as *const isize as usize; + tx.send(x_in_child).unwrap(); + }); + + let x_in_child = rx.recv().unwrap(); + assert_eq!(x_in_parent, x_in_child); + + t.join(); +} diff --git a/tests/ui/threads-sendsync/task-stderr.rs b/tests/ui/threads-sendsync/task-stderr.rs new file mode 100644 index 000000000..68d226ffb --- /dev/null +++ b/tests/ui/threads-sendsync/task-stderr.rs @@ -0,0 +1,26 @@ +// run-pass +// ignore-emscripten no threads support +// needs-unwind + +#![feature(internal_output_capture)] + +use std::io; +use std::str; +use std::sync::{Arc, Mutex}; +use std::thread; + +fn main() { + let data = Arc::new(Mutex::new(Vec::new())); + let res = thread::Builder::new().spawn({ + let data = data.clone(); + move || { + io::set_output_capture(Some(data)); + panic!("Hello, world!") + } + }).unwrap().join(); + assert!(res.is_err()); + + let output = data.lock().unwrap(); + let output = str::from_utf8(&output).unwrap(); + assert!(output.contains("Hello, world!")); +} diff --git a/tests/ui/threads-sendsync/tcp-stress.rs b/tests/ui/threads-sendsync/tcp-stress.rs new file mode 100644 index 000000000..175663643 --- /dev/null +++ b/tests/ui/threads-sendsync/tcp-stress.rs @@ -0,0 +1,64 @@ +// run-pass +// ignore-android needs extra network permissions +// ignore-emscripten no threads or sockets support +// ignore-netbsd system ulimit (Too many open files) +// ignore-openbsd system ulimit (Too many open files) + +use std::io::prelude::*; +use std::net::{TcpListener, TcpStream}; +use std::process; +use std::sync::mpsc::channel; +use std::time::Duration; +use std::thread::{self, Builder}; + +const TARGET_CNT: usize = 200; + +fn main() { + // This test has a chance to time out, try to not let it time out + thread::spawn(move|| -> () { + thread::sleep(Duration::from_secs(30)); + process::exit(1); + }); + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + thread::spawn(move || -> () { + loop { + let mut stream = match listener.accept() { + Ok(stream) => stream.0, + Err(_) => continue, + }; + let _ = stream.read(&mut [0]); + let _ = stream.write(&[2]); + } + }); + + let (tx, rx) = channel(); + + let mut spawned_cnt = 0; + for _ in 0..TARGET_CNT { + let tx = tx.clone(); + let res = Builder::new().stack_size(64 * 1024).spawn(move|| { + match TcpStream::connect(addr) { + Ok(mut stream) => { + let _ = stream.write(&[1]); + let _ = stream.read(&mut [0]); + }, + Err(..) => {} + } + tx.send(()).unwrap(); + }); + if let Ok(_) = res { + spawned_cnt += 1; + }; + } + + // Wait for all clients to exit, but don't wait for the server to exit. The + // server just runs infinitely. + drop(tx); + for _ in 0..spawned_cnt { + rx.recv().unwrap(); + } + assert_eq!(spawned_cnt, TARGET_CNT); + process::exit(0); +} diff --git a/tests/ui/threads-sendsync/test-tasks-invalid-value.rs b/tests/ui/threads-sendsync/test-tasks-invalid-value.rs new file mode 100644 index 000000000..641142142 --- /dev/null +++ b/tests/ui/threads-sendsync/test-tasks-invalid-value.rs @@ -0,0 +1,11 @@ +// This checks that RUST_TEST_THREADS not being 1, 2, ... is detected +// properly. + +// run-fail +// error-pattern:should be a positive integer +// compile-flags: --test +// exec-env:RUST_TEST_THREADS=foo +// ignore-emscripten + +#[test] +fn do_nothing() {} diff --git a/tests/ui/threads-sendsync/thread-local-extern-static.rs b/tests/ui/threads-sendsync/thread-local-extern-static.rs new file mode 100644 index 000000000..a2dda31aa --- /dev/null +++ b/tests/ui/threads-sendsync/thread-local-extern-static.rs @@ -0,0 +1,27 @@ +// run-pass +// ignore-windows +// aux-build:thread-local-extern-static.rs + +#![feature(cfg_target_thread_local, thread_local)] + +#[cfg(target_thread_local)] +extern crate thread_local_extern_static; + +#[cfg(target_thread_local)] +use std::cell::Cell; + +#[cfg(target_thread_local)] +extern "C" { + #[thread_local] + static FOO: Cell<u32>; +} + +#[cfg(target_thread_local)] +fn main() { + unsafe { + assert_eq!(FOO.get(), 3); + } +} + +#[cfg(not(target_thread_local))] +fn main() {} diff --git a/tests/ui/threads-sendsync/thread-local-syntax.rs b/tests/ui/threads-sendsync/thread-local-syntax.rs new file mode 100644 index 000000000..2f4805e47 --- /dev/null +++ b/tests/ui/threads-sendsync/thread-local-syntax.rs @@ -0,0 +1,22 @@ +// run-pass +#![deny(missing_docs)] +//! this tests the syntax of `thread_local!` + +mod foo { + mod bar { + thread_local! { + // no docs + #[allow(unused)] + static FOO: i32 = 42; + /// docs + pub static BAR: String = String::from("bar"); + + // look at these restrictions!! + pub(crate) static BAZ: usize = 0; + pub(in foo) static QUUX: usize = 0; + } + thread_local!(static SPLOK: u32 = 0); + } +} + +fn main() {} diff --git a/tests/ui/threads-sendsync/threads.rs b/tests/ui/threads-sendsync/threads.rs new file mode 100644 index 000000000..e3da83aa1 --- /dev/null +++ b/tests/ui/threads-sendsync/threads.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + let mut i = 10; + while i > 0 { + thread::spawn({let i = i; move|| child(i)}).join(); + i = i - 1; + } + println!("main thread exiting"); +} + +fn child(x: isize) { println!("{}", x); } diff --git a/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs b/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs new file mode 100644 index 000000000..8baef4334 --- /dev/null +++ b/tests/ui/threads-sendsync/tls-dtors-are-run-in-a-static-binary.rs @@ -0,0 +1,22 @@ +// run-pass +// no-prefer-dynamic +// ignore-emscripten no threads support + +static mut HIT: bool = false; + +struct Foo; + +impl Drop for Foo { + fn drop(&mut self) { + unsafe { HIT = true; } + } +} + +thread_local!(static FOO: Foo = Foo); + +fn main() { + std::thread::spawn(|| { + FOO.with(|_| {}); + }).join().unwrap(); + assert!(unsafe { HIT }); +} diff --git a/tests/ui/threads-sendsync/tls-init-on-init.rs b/tests/ui/threads-sendsync/tls-init-on-init.rs new file mode 100644 index 000000000..193c18151 --- /dev/null +++ b/tests/ui/threads-sendsync/tls-init-on-init.rs @@ -0,0 +1,44 @@ +// run-pass +#![allow(stable_features)] + +// ignore-emscripten no threads support + +#![feature(thread_local_try_with)] + +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; + +struct Foo { cnt: usize } + +thread_local!(static FOO: Foo = Foo::init()); + +static CNT: AtomicUsize = AtomicUsize::new(0); + +impl Foo { + fn init() -> Foo { + let cnt = CNT.fetch_add(1, Ordering::SeqCst); + if cnt == 0 { + FOO.with(|_| {}); + } + Foo { cnt: cnt } + } +} + +impl Drop for Foo { + fn drop(&mut self) { + if self.cnt == 1 { + FOO.with(|foo| assert_eq!(foo.cnt, 0)); + } else { + assert_eq!(self.cnt, 0); + if FOO.try_with(|_| ()).is_ok() { + panic!("should not be in valid state"); + } + } + } +} + +fn main() { + thread::spawn(|| { + FOO.with(|_| {}); + }).join().unwrap(); +} diff --git a/tests/ui/threads-sendsync/tls-try-with.rs b/tests/ui/threads-sendsync/tls-try-with.rs new file mode 100644 index 000000000..f36ab4e4f --- /dev/null +++ b/tests/ui/threads-sendsync/tls-try-with.rs @@ -0,0 +1,30 @@ +// run-pass +#![allow(stable_features)] + +// ignore-emscripten no threads support + +#![feature(thread_local_try_with)] + +use std::thread; + +static mut DROP_RUN: bool = false; + +struct Foo; + +thread_local!(static FOO: Foo = Foo {}); + +impl Drop for Foo { + fn drop(&mut self) { + assert!(FOO.try_with(|_| panic!("`try_with` closure run")).is_err()); + unsafe { DROP_RUN = true; } + } +} + +fn main() { + thread::spawn(|| { + assert_eq!(FOO.try_with(|_| { + 132 + }).expect("`try_with` failed"), 132); + }).join().unwrap(); + assert!(unsafe { DROP_RUN }); +} diff --git a/tests/ui/threads-sendsync/trivial-message.rs b/tests/ui/threads-sendsync/trivial-message.rs new file mode 100644 index 000000000..5831e867b --- /dev/null +++ b/tests/ui/threads-sendsync/trivial-message.rs @@ -0,0 +1,16 @@ +// run-pass + +#![allow(unused_must_use)] +/* + This is about the simplest program that can successfully send a + message. + */ + +use std::sync::mpsc::channel; + +pub fn main() { + let (tx, rx) = channel(); + tx.send(42); + let r = rx.recv(); + println!("{:?}", r); +} diff --git a/tests/ui/threads-sendsync/unwind-resource.rs b/tests/ui/threads-sendsync/unwind-resource.rs new file mode 100644 index 000000000..6950a9c40 --- /dev/null +++ b/tests/ui/threads-sendsync/unwind-resource.rs @@ -0,0 +1,40 @@ +// run-pass +// needs-unwind + +#![allow(non_camel_case_types)] +// ignore-emscripten no threads support + +use std::sync::mpsc::{channel, Sender}; +use std::thread; + +struct complainer { + tx: Sender<bool>, +} + +impl Drop for complainer { + fn drop(&mut self) { + println!("About to send!"); + self.tx.send(true).unwrap(); + println!("Sent!"); + } +} + +fn complainer(tx: Sender<bool>) -> complainer { + println!("Hello!"); + complainer { + tx: tx + } +} + +fn f(tx: Sender<bool>) { + let _tx = complainer(tx); + panic!(); +} + +pub fn main() { + let (tx, rx) = channel(); + let t = thread::spawn(move|| f(tx.clone())); + println!("hiiiiiiiii"); + assert!(rx.recv().unwrap()); + drop(t.join()); +} diff --git a/tests/ui/threads-sendsync/yield.rs b/tests/ui/threads-sendsync/yield.rs new file mode 100644 index 000000000..e83ba5560 --- /dev/null +++ b/tests/ui/threads-sendsync/yield.rs @@ -0,0 +1,21 @@ +// run-pass + +#![allow(unused_must_use)] +#![allow(unused_mut)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + let mut result = thread::spawn(child); + println!("1"); + thread::yield_now(); + println!("2"); + thread::yield_now(); + println!("3"); + result.join(); +} + +fn child() { + println!("4"); thread::yield_now(); println!("5"); thread::yield_now(); println!("6"); +} diff --git a/tests/ui/threads-sendsync/yield1.rs b/tests/ui/threads-sendsync/yield1.rs new file mode 100644 index 000000000..002e59055 --- /dev/null +++ b/tests/ui/threads-sendsync/yield1.rs @@ -0,0 +1,16 @@ +// run-pass + +#![allow(unused_must_use)] +#![allow(unused_mut)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + let mut result = thread::spawn(child); + println!("1"); + thread::yield_now(); + result.join(); +} + +fn child() { println!("2"); } diff --git a/tests/ui/threads-sendsync/yield2.rs b/tests/ui/threads-sendsync/yield2.rs new file mode 100644 index 000000000..376faab0c --- /dev/null +++ b/tests/ui/threads-sendsync/yield2.rs @@ -0,0 +1,8 @@ +// run-pass + +use std::thread; + +pub fn main() { + let mut i: isize = 0; + while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); } +} |