11
11
#![ cfg( target_thread_local) ]
12
12
#![ unstable( feature = "thread_local_internals" , issue = "0" ) ]
13
13
14
- use cell:: { Cell , UnsafeCell } ;
15
- use fmt;
16
- use mem;
17
- use ptr;
18
-
19
- pub struct Key < T > {
20
- inner : UnsafeCell < Option < T > > ,
21
-
22
- // Metadata to keep track of the state of the destructor. Remember that
23
- // these variables are thread-local, not global.
24
- dtor_registered : Cell < bool > ,
25
- dtor_running : Cell < bool > ,
26
- }
27
-
28
- impl < T > fmt:: Debug for Key < T > {
29
- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
30
- f. pad ( "Key { .. }" )
31
- }
32
- }
33
-
34
- unsafe impl < T > :: marker:: Sync for Key < T > { }
35
-
36
- impl < T > Key < T > {
37
- pub const fn new ( ) -> Key < T > {
38
- Key {
39
- inner : UnsafeCell :: new ( None ) ,
40
- dtor_registered : Cell :: new ( false ) ,
41
- dtor_running : Cell :: new ( false )
42
- }
43
- }
44
-
45
- pub fn get ( & ' static self ) -> Option < & ' static UnsafeCell < Option < T > > > {
46
- unsafe {
47
- if mem:: needs_drop :: < T > ( ) && self . dtor_running . get ( ) {
48
- return None
49
- }
50
- self . register_dtor ( ) ;
51
- }
52
- Some ( & self . inner )
53
- }
54
-
55
- unsafe fn register_dtor ( & self ) {
56
- if !mem:: needs_drop :: < T > ( ) || self . dtor_registered . get ( ) {
57
- return
58
- }
59
-
60
- register_dtor ( self as * const _ as * mut u8 ,
61
- destroy_value :: < T > ) ;
62
- self . dtor_registered . set ( true ) ;
63
- }
64
- }
65
-
66
- #[ cfg( any( target_os = "linux" , target_os = "fuchsia" ) ) ]
67
- unsafe fn register_dtor_fallback ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
68
- // The fallback implementation uses a vanilla OS-based TLS key to track
69
- // the list of destructors that need to be run for this thread. The key
70
- // then has its own destructor which runs all the other destructors.
71
- //
72
- // The destructor for DTORS is a little special in that it has a `while`
73
- // loop to continuously drain the list of registered destructors. It
74
- // *should* be the case that this loop always terminates because we
75
- // provide the guarantee that a TLS key cannot be set after it is
76
- // flagged for destruction.
77
- use sys_common:: thread_local as os;
78
-
79
- static DTORS : os:: StaticKey = os:: StaticKey :: new ( Some ( run_dtors) ) ;
80
- type List = Vec < ( * mut u8 , unsafe extern fn ( * mut u8 ) ) > ;
81
- if DTORS . get ( ) . is_null ( ) {
82
- let v: Box < List > = box Vec :: new ( ) ;
83
- DTORS . set ( Box :: into_raw ( v) as * mut u8 ) ;
84
- }
85
- let list: & mut List = & mut * ( DTORS . get ( ) as * mut List ) ;
86
- list. push ( ( t, dtor) ) ;
87
-
88
- unsafe extern fn run_dtors ( mut ptr : * mut u8 ) {
89
- while !ptr. is_null ( ) {
90
- let list: Box < List > = Box :: from_raw ( ptr as * mut List ) ;
91
- for & ( ptr, dtor) in list. iter ( ) {
92
- dtor ( ptr) ;
93
- }
94
- ptr = DTORS . get ( ) ;
95
- DTORS . set ( ptr:: null_mut ( ) ) ;
96
- }
97
- }
98
- }
99
-
100
14
// Since what appears to be glibc 2.18 this symbol has been shipped which
101
15
// GCC and clang both use to invoke destructors in thread_local globals, so
102
16
// let's do the same!
@@ -107,9 +21,10 @@ unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
107
21
//
108
22
// Due to rust-lang/rust#18804, make sure this is not generic!
109
23
#[ cfg( target_os = "linux" ) ]
110
- unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
111
- use mem;
24
+ pub unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
112
25
use libc;
26
+ use mem;
27
+ use sys_common:: thread_local:: register_dtor_fallback;
113
28
114
29
extern {
115
30
#[ linkage = "extern_weak" ]
@@ -132,7 +47,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
132
47
// The disassembly of thread_local globals in C++ (at least produced by
133
48
// clang) will have this show up in the output.
134
49
#[ cfg( target_os = "macos" ) ]
135
- unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
50
+ pub unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
136
51
extern {
137
52
fn _tlv_atexit ( dtor : unsafe extern fn ( * mut u8 ) ,
138
53
arg : * mut u8 ) ;
@@ -143,17 +58,9 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
143
58
// Just use the thread_local fallback implementation, at least until there's
144
59
// a more direct implementation.
145
60
#[ cfg( target_os = "fuchsia" ) ]
146
- unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
147
- register_dtor_fallback ( t, dtor) ;
148
- }
149
-
150
- pub unsafe extern fn destroy_value < T > ( ptr : * mut u8 ) {
151
- let ptr = ptr as * mut Key < T > ;
152
- // Right before we run the user destructor be sure to flag the
153
- // destructor as running for this thread so calls to `get` will return
154
- // `None`.
155
- ( * ptr) . dtor_running . set ( true ) ;
61
+ pub use sys_common:: thread_local:: register_dtor_fallback as register_dtor;
156
62
63
+ pub fn requires_move_before_drop ( ) -> bool {
157
64
// The macOS implementation of TLS apparently had an odd aspect to it
158
65
// where the pointer we have may be overwritten while this destructor
159
66
// is running. Specifically if a TLS destructor re-accesses TLS it may
@@ -166,9 +73,5 @@ pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
166
73
//
167
74
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
168
75
// instead of drop_in_place.
169
- if cfg ! ( target_os = "macos" ) {
170
- ptr:: read ( ( * ptr) . inner . get ( ) ) ;
171
- } else {
172
- ptr:: drop_in_place ( ( * ptr) . inner . get ( ) ) ;
173
- }
76
+ cfg ! ( target_os = "macos" )
174
77
}
0 commit comments