blob: effb6a143f91558a4c0e7fd029a9143bfb0c87b4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
//! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics.
#![cfg(not(miri))] // error: abnormal termination: the evaluated program aborted execution
use std::thread;
use std::time::Duration;
use crossbeam_channel::{select, unbounded};
use crossbeam_utils::thread::scope;
fn ms(ms: u64) -> Duration {
Duration::from_millis(ms)
}
#[test]
#[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")]
fn use_while_exiting() {
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
// A blocking operation after the thread-locals have been dropped. This will attempt to
// use the thread-locals and must not panic.
let (_s, r) = unbounded::<()>();
select! {
recv(r) -> _ => {}
default(ms(100)) => {}
}
}
}
thread_local! {
static FOO: Foo = Foo;
}
let (s, r) = unbounded::<()>();
scope(|scope| {
scope.spawn(|_| {
// First initialize `FOO`, then the thread-locals related to crossbeam-channel.
FOO.with(|_| ());
r.recv().unwrap();
// At thread exit, thread-locals related to crossbeam-channel get dropped first and
// `FOO` is dropped last.
});
scope.spawn(|_| {
thread::sleep(ms(100));
s.send(()).unwrap();
});
})
.unwrap();
}
|