33//! that will run all native TLS destructors in the destructor list.
44
55use crate :: ptr;
6+ use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
7+ use crate :: sys:: thread_local:: exit:: at_process_exit;
68use crate :: sys:: thread_local:: key:: { LazyKey , set} ;
79
810#[ cfg( target_thread_local) ]
911pub fn enable ( ) {
10- use crate :: sys:: thread_local:: destructors;
12+ fn enable_thread ( ) {
13+ static DTORS : LazyKey = LazyKey :: new ( Some ( run_thread) ) ;
1114
12- static DTORS : LazyKey = LazyKey :: new ( Some ( run) ) ;
15+ // Setting the key value to something other than NULL will result in the
16+ // destructor being run at thread exit.
17+ unsafe {
18+ set ( DTORS . force ( ) , ptr:: without_provenance_mut ( 1 ) ) ;
19+ }
20+
21+ unsafe extern "C" fn run_thread ( _: * mut u8 ) {
22+ run ( )
23+ }
24+ }
1325
14- // Setting the key value to something other than NULL will result in the
15- // destructor being run at thread exit.
16- unsafe {
17- set ( DTORS . force ( ) , ptr:: without_provenance_mut ( 1 ) ) ;
26+ fn enable_process ( ) {
27+ static REGISTERED : AtomicBool = AtomicBool :: new ( false ) ;
28+ if !REGISTERED . swap ( true , Ordering :: Relaxed ) {
29+ unsafe { at_process_exit ( run_process) } ;
30+ }
31+
32+ unsafe extern "C" fn run_process ( ) {
33+ run ( )
34+ }
1835 }
1936
20- unsafe extern "C" fn run ( _: * mut u8 ) {
37+ fn run ( ) {
38+ use crate :: sys:: thread_local:: destructors;
39+
2140 unsafe {
2241 destructors:: run ( ) ;
2342 // On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
@@ -28,33 +47,55 @@ pub fn enable() {
2847 crate :: rt:: thread_cleanup ( ) ;
2948 }
3049 }
50+
51+ enable_thread ( ) ;
52+ enable_process ( ) ;
3153}
3254
3355/// On platforms with key-based TLS, the system runs the destructors for us.
3456/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
3557/// however. This is done by defering the execution of a TLS destructor to
3658/// the next round of destruction inside the TLS destructors.
59+ ///
60+ /// POSIX systems do not run TLS destructors at process exit.
61+ /// Thus we register our own callback to invoke them in that case.
3762#[ cfg( not( target_thread_local) ) ]
3863pub fn enable ( ) {
39- const DEFER : * mut u8 = ptr:: without_provenance_mut ( 1 ) ;
40- const RUN : * mut u8 = ptr:: without_provenance_mut ( 2 ) ;
41-
42- static CLEANUP : LazyKey = LazyKey :: new ( Some ( run) ) ;
43-
44- unsafe { set ( CLEANUP . force ( ) , DEFER ) }
45-
46- unsafe extern "C" fn run ( state : * mut u8 ) {
47- if state == DEFER {
48- // Make sure that this function is run again in the next round of
49- // TLS destruction. If there is no futher round, there will be leaks,
50- // but that's okay, `thread_cleanup` is not guaranteed to be called.
51- unsafe { set ( CLEANUP . force ( ) , RUN ) }
52- } else {
53- debug_assert_eq ! ( state, RUN ) ;
54- // If the state is still RUN in the next round of TLS destruction,
55- // it means that no other TLS destructors defined by this runtime
56- // have been run, as they would have set the state to DEFER.
57- crate :: rt:: thread_cleanup ( ) ;
64+ fn enable_thread ( ) {
65+ const DEFER : * mut u8 = ptr:: without_provenance_mut ( 1 ) ;
66+ const RUN : * mut u8 = ptr:: without_provenance_mut ( 2 ) ;
67+
68+ static CLEANUP : LazyKey = LazyKey :: new ( Some ( run_thread) ) ;
69+
70+ unsafe { set ( CLEANUP . force ( ) , DEFER ) }
71+
72+ unsafe extern "C" fn run_thread ( state : * mut u8 ) {
73+ if state == DEFER {
74+ // Make sure that this function is run again in the next round of
75+ // TLS destruction. If there is no futher round, there will be leaks,
76+ // but that's okay, `thread_cleanup` is not guaranteed to be called.
77+ unsafe { set ( CLEANUP . force ( ) , RUN ) }
78+ } else {
79+ debug_assert_eq ! ( state, RUN ) ;
80+ // If the state is still RUN in the next round of TLS destruction,
81+ // it means that no other TLS destructors defined by this runtime
82+ // have been run, as they would have set the state to DEFER.
83+ crate :: rt:: thread_cleanup ( ) ;
84+ }
85+ }
86+ }
87+
88+ fn enable_process ( ) {
89+ static REGISTERED : AtomicBool = AtomicBool :: new ( false ) ;
90+ if !REGISTERED . swap ( true , Ordering :: Relaxed ) {
91+ unsafe { at_process_exit ( run_process) } ;
92+ }
93+
94+ unsafe extern "C" fn run_process ( ) {
95+ unsafe { crate :: sys:: thread_local:: key:: run_dtors ( ) } ;
5896 }
5997 }
98+
99+ enable_thread ( ) ;
100+ enable_process ( ) ;
60101}
0 commit comments