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