44use std:: cell:: RefCell ;
55use std:: thread;
66
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+ }
1013
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( ) )
1520 }
16- println ! ( "Dropping: {} (should be before 'Continue main 1')." , * self . value. borrow( ) )
1721 }
18- }
1922
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+ }
2428
25- /// Check that destructors of the library thread locals are executed immediately
26- /// after a thread terminates.
27- fn check_destructors ( ) {
2829 // We use the same value for both of them, since destructor order differs between Miri on Linux
2930 // (which uses `register_dtor_fallback`, in the end using a single pthread_key to manage a
3031 // thread-local linked list of dtors to call), real Linux rustc (which uses
@@ -44,26 +45,29 @@ fn check_destructors() {
4445 println ! ( "Continue main 1." )
4546}
4647
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+ }
5053
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+ ) ;
5564 }
56- let join_handle = self . value . borrow_mut ( ) . take ( ) . unwrap ( ) ;
57- println ! ( "Joining: {} (should be before 'Continue main 2')." , join_handle. join( ) . unwrap( ) ) ;
5865 }
59- }
6066
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+ }
6470
65- /// Check that the destructor can be blocked joining another thread.
66- fn check_blocking ( ) {
6771 thread:: spawn ( || {
6872 B . with ( |f| {
6973 assert ! ( f. value. borrow( ) . is_none( ) ) ;
@@ -74,10 +78,36 @@ fn check_blocking() {
7478 . join ( )
7579 . unwrap ( ) ;
7680 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." ) ;
81111}
82112
83113// This test tests that TLS destructors have run before the thread joins. The
@@ -248,6 +278,8 @@ fn dtors_in_dtors_in_dtors() {
248278fn main ( ) {
249279 check_destructors ( ) ;
250280 check_blocking ( ) ;
281+ check_tls_init_in_dtor ( ) ;
282+
251283 join_orders_after_tls_destructors ( ) ;
252284 dtors_in_dtors_in_dtors ( ) ;
253285}
0 commit comments