3
3
//! that will run all native TLS destructors in the destructor list.
4
4
5
5
use crate :: ptr;
6
+ use crate :: sync:: atomic:: { AtomicBool , Ordering } ;
7
+ use crate :: sys:: thread_local:: exit:: at_process_exit;
6
8
use crate :: sys:: thread_local:: key:: { LazyKey , set} ;
7
9
8
10
#[ cfg( target_thread_local) ]
9
11
pub fn enable ( ) {
10
- use crate :: sys:: thread_local:: destructors;
12
+ fn enable_thread ( ) {
13
+ static DTORS : LazyKey = LazyKey :: new ( Some ( run_thread) ) ;
11
14
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
+ }
13
25
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
+ }
18
35
}
19
36
20
- unsafe extern "C" fn run ( _: * mut u8 ) {
37
+ fn run ( ) {
38
+ use crate :: sys:: thread_local:: destructors;
39
+
21
40
unsafe {
22
41
destructors:: run ( ) ;
23
42
// On platforms with `__cxa_thread_atexit_impl`, `destructors::run`
@@ -28,33 +47,55 @@ pub fn enable() {
28
47
crate :: rt:: thread_cleanup ( ) ;
29
48
}
30
49
}
50
+
51
+ enable_thread ( ) ;
52
+ enable_process ( ) ;
31
53
}
32
54
33
55
/// On platforms with key-based TLS, the system runs the destructors for us.
34
56
/// We still have to make sure that [`crate::rt::thread_cleanup`] is called,
35
57
/// however. This is done by defering the execution of a TLS destructor to
36
58
/// 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.
37
62
#[ cfg( not( target_thread_local) ) ]
38
63
pub 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 ( ) } ;
58
96
}
59
97
}
98
+
99
+ enable_thread ( ) ;
100
+ enable_process ( ) ;
60
101
}
0 commit comments