4
4
use std:: cell:: RefCell ;
5
5
use std:: thread;
6
6
7
- struct TestCell {
8
- value : RefCell < u8 > ,
9
- }
7
+ /// Check that destructors of the library thread locals are executed immediately
8
+ /// after a thread terminates.
9
+ fn check_destructors ( ) {
10
+ struct TestCell {
11
+ value : RefCell < u8 > ,
12
+ }
10
13
11
- impl Drop for TestCell {
12
- fn drop ( & mut self ) {
13
- for _ in 0 ..10 {
14
- thread:: yield_now ( ) ;
14
+ impl Drop for TestCell {
15
+ fn drop ( & mut self ) {
16
+ for _ in 0 ..10 {
17
+ thread:: yield_now ( ) ;
18
+ }
19
+ println ! ( "Dropping: {} (should be before 'Continue main 1')." , * self . value. borrow( ) )
15
20
}
16
- println ! ( "Dropping: {} (should be before 'Continue main 1')." , * self . value. borrow( ) )
17
21
}
18
- }
19
22
20
- thread_local ! {
21
- static A : TestCell = TestCell { value: RefCell :: new( 0 ) } ;
22
- static A_CONST : TestCell = const { TestCell { value: RefCell :: new( 10 ) } } ;
23
- }
23
+ // Test both regular and `const` thread-locals.
24
+ thread_local ! {
25
+ static A : TestCell = TestCell { value: RefCell :: new( 0 ) } ;
26
+ static A_CONST : TestCell = const { TestCell { value: RefCell :: new( 10 ) } } ;
27
+ }
24
28
25
- /// Check that destructors of the library thread locals are executed immediately
26
- /// after a thread terminates.
27
- fn check_destructors ( ) {
28
29
// We use the same value for both of them, since destructor order differs between Miri on Linux
29
30
// (which uses `register_dtor_fallback`, in the end using a single pthread_key to manage a
30
31
// thread-local linked list of dtors to call), real Linux rustc (which uses
@@ -44,26 +45,29 @@ fn check_destructors() {
44
45
println ! ( "Continue main 1." )
45
46
}
46
47
47
- struct JoinCell {
48
- value : RefCell < Option < thread:: JoinHandle < u8 > > > ,
49
- }
48
+ /// Check that the destructor can be blocked joining another thread.
49
+ fn check_blocking ( ) {
50
+ struct JoinCell {
51
+ value : RefCell < Option < thread:: JoinHandle < u8 > > > ,
52
+ }
50
53
51
- impl Drop for JoinCell {
52
- fn drop ( & mut self ) {
53
- for _ in 0 ..10 {
54
- thread:: yield_now ( ) ;
54
+ impl Drop for JoinCell {
55
+ fn drop ( & mut self ) {
56
+ for _ in 0 ..10 {
57
+ thread:: yield_now ( ) ;
58
+ }
59
+ let join_handle = self . value . borrow_mut ( ) . take ( ) . unwrap ( ) ;
60
+ println ! (
61
+ "Joining: {} (should be before 'Continue main 2')." ,
62
+ join_handle. join( ) . unwrap( )
63
+ ) ;
55
64
}
56
- let join_handle = self . value . borrow_mut ( ) . take ( ) . unwrap ( ) ;
57
- println ! ( "Joining: {} (should be before 'Continue main 2')." , join_handle. join( ) . unwrap( ) ) ;
58
65
}
59
- }
60
66
61
- thread_local ! {
62
- static B : JoinCell = JoinCell { value: RefCell :: new( None ) } ;
63
- }
67
+ thread_local ! {
68
+ static B : JoinCell = JoinCell { value: RefCell :: new( None ) } ;
69
+ }
64
70
65
- /// Check that the destructor can be blocked joining another thread.
66
- fn check_blocking ( ) {
67
71
thread:: spawn ( || {
68
72
B . with ( |f| {
69
73
assert ! ( f. value. borrow( ) . is_none( ) ) ;
@@ -74,10 +78,36 @@ fn check_blocking() {
74
78
. join ( )
75
79
. unwrap ( ) ;
76
80
println ! ( "Continue main 2." ) ;
77
- // Preempt the main thread so that the destructor gets executed and can join
78
- // the thread.
79
- thread:: yield_now ( ) ;
80
- thread:: yield_now ( ) ;
81
+ }
82
+
83
+ fn check_tls_init_in_dtor ( ) {
84
+ struct Bar ;
85
+
86
+ impl Drop for Bar {
87
+ fn drop ( & mut self ) {
88
+ println ! ( "Bar dtor (should be before `Continue main 3`)." ) ;
89
+ }
90
+ }
91
+
92
+ struct Foo ;
93
+
94
+ impl Drop for Foo {
95
+ fn drop ( & mut self ) {
96
+ println ! ( "Foo dtor (should be before `Bar dtor`)." ) ;
97
+ // We initialize another thread-local inside the dtor, which is an interesting corner case.
98
+ thread_local ! ( static BAR : Bar = Bar ) ;
99
+ BAR . with ( |_| { } ) ;
100
+ }
101
+ }
102
+
103
+ thread_local ! ( static FOO : Foo = Foo ) ;
104
+
105
+ thread:: spawn ( || {
106
+ FOO . with ( |_| { } ) ;
107
+ } )
108
+ . join ( )
109
+ . unwrap ( ) ;
110
+ println ! ( "Continue main 3." ) ;
81
111
}
82
112
83
113
// This test tests that TLS destructors have run before the thread joins. The
@@ -248,6 +278,8 @@ fn dtors_in_dtors_in_dtors() {
248
278
fn main ( ) {
249
279
check_destructors ( ) ;
250
280
check_blocking ( ) ;
281
+ check_tls_init_in_dtor ( ) ;
282
+
251
283
join_orders_after_tls_destructors ( ) ;
252
284
dtors_in_dtors_in_dtors ( ) ;
253
285
}
0 commit comments