1111#![ cfg( target_thread_local) ]
1212#![ unstable( feature = "thread_local_internals" , issue = "0" ) ]
1313
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-
10014// Since what appears to be glibc 2.18 this symbol has been shipped which
10115// GCC and clang both use to invoke destructors in thread_local globals, so
10216// let's do the same!
@@ -107,9 +21,10 @@ unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
10721//
10822// Due to rust-lang/rust#18804, make sure this is not generic!
10923#[ 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 ) ) {
11225 use libc;
26+ use mem;
27+ use sys_common:: thread_local:: register_dtor_fallback;
11328
11429 extern {
11530 #[ linkage = "extern_weak" ]
@@ -132,7 +47,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
13247// The disassembly of thread_local globals in C++ (at least produced by
13348// clang) will have this show up in the output.
13449#[ 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 ) ) {
13651 extern {
13752 fn _tlv_atexit ( dtor : unsafe extern fn ( * mut u8 ) ,
13853 arg : * mut u8 ) ;
@@ -143,17 +58,9 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
14358// Just use the thread_local fallback implementation, at least until there's
14459// a more direct implementation.
14560#[ 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;
15662
63+ pub fn requires_move_before_drop ( ) -> bool {
15764 // The macOS implementation of TLS apparently had an odd aspect to it
15865 // where the pointer we have may be overwritten while this destructor
15966 // 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) {
16673 //
16774 // Hence, we use `ptr::read` on macOS (to move to a "safe" location)
16875 // 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" )
17477}
0 commit comments