2020-04-19 22:52:53 -05:00
|
|
|
// ignore-windows: Concurrency on Windows is not supported yet.
|
|
|
|
|
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::thread;
|
|
|
|
|
|
|
|
struct TestCell {
|
|
|
|
value: RefCell<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for TestCell {
|
|
|
|
fn drop(&mut self) {
|
2020-07-26 08:53:02 -05:00
|
|
|
for _ in 0..10 { thread::yield_now(); }
|
|
|
|
println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow())
|
2020-04-19 22:52:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-20 19:23:51 -05:00
|
|
|
thread_local! {
|
|
|
|
static A: TestCell = TestCell { value: RefCell::new(0) };
|
2021-04-18 03:57:56 -05:00
|
|
|
static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } };
|
2020-04-20 19:23:51 -05:00
|
|
|
}
|
2020-04-19 22:52:53 -05:00
|
|
|
|
2020-04-27 00:05:09 -05:00
|
|
|
/// Check that destructors of the library thread locals are executed immediately
|
|
|
|
/// after a thread terminates.
|
|
|
|
fn check_destructors() {
|
2020-04-19 22:52:53 -05:00
|
|
|
thread::spawn(|| {
|
|
|
|
A.with(|f| {
|
|
|
|
assert_eq!(*f.value.borrow(), 0);
|
|
|
|
*f.value.borrow_mut() = 5;
|
|
|
|
});
|
2021-04-18 03:57:56 -05:00
|
|
|
A_CONST.with(|f| {
|
|
|
|
assert_eq!(*f.value.borrow(), 10);
|
|
|
|
*f.value.borrow_mut() = 15;
|
|
|
|
});
|
2020-04-19 22:52:53 -05:00
|
|
|
})
|
|
|
|
.join()
|
|
|
|
.unwrap();
|
2020-07-26 08:53:02 -05:00
|
|
|
println!("Continue main 1.")
|
2020-04-19 22:52:53 -05:00
|
|
|
}
|
2020-04-27 00:05:09 -05:00
|
|
|
|
|
|
|
struct JoinCell {
|
|
|
|
value: RefCell<Option<thread::JoinHandle<u8>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for JoinCell {
|
|
|
|
fn drop(&mut self) {
|
2020-07-26 08:53:02 -05:00
|
|
|
for _ in 0..10 { thread::yield_now(); }
|
2020-04-27 00:05:09 -05:00
|
|
|
let join_handle = self.value.borrow_mut().take().unwrap();
|
2020-07-26 08:53:02 -05:00
|
|
|
println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap());
|
2020-04-27 00:05:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
thread_local! {
|
|
|
|
static B: JoinCell = JoinCell { value: RefCell::new(None) };
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that the destructor can be blocked joining another thread.
|
|
|
|
fn check_blocking() {
|
|
|
|
thread::spawn(|| {
|
|
|
|
B.with(|f| {
|
|
|
|
assert!(f.value.borrow().is_none());
|
|
|
|
let handle = thread::spawn(|| 7);
|
|
|
|
*f.value.borrow_mut() = Some(handle);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.join()
|
|
|
|
.unwrap();
|
|
|
|
println!("Continue main 2.");
|
|
|
|
// Preempt the main thread so that the destructor gets executed and can join
|
|
|
|
// the thread.
|
|
|
|
thread::yield_now();
|
|
|
|
thread::yield_now();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
check_destructors();
|
|
|
|
check_blocking();
|
|
|
|
}
|