1
1
#![ cfg( target_thread_local) ]
2
2
#![ unstable( feature = "thread_local_internals" , issue = "0" ) ]
3
3
4
- use crate :: cell:: { Cell , UnsafeCell } ;
5
- use crate :: mem;
6
- use crate :: ptr;
7
-
8
-
9
- pub struct Key < T > {
10
- inner : UnsafeCell < Option < T > > ,
11
-
12
- // Metadata to keep track of the state of the destructor. Remember that
13
- // these variables are thread-local, not global.
14
- dtor_registered : Cell < bool > ,
15
- dtor_running : Cell < bool > ,
16
- }
17
-
18
- unsafe impl < T > Sync for Key < T > { }
19
-
20
- impl < T > Key < T > {
21
- pub const fn new ( ) -> Key < T > {
22
- Key {
23
- inner : UnsafeCell :: new ( None ) ,
24
- dtor_registered : Cell :: new ( false ) ,
25
- dtor_running : Cell :: new ( false )
26
- }
27
- }
28
-
29
- pub fn get ( & ' static self ) -> Option < & ' static UnsafeCell < Option < T > > > {
30
- unsafe {
31
- if mem:: needs_drop :: < T > ( ) && self . dtor_running . get ( ) {
32
- return None
33
- }
34
- self . register_dtor ( ) ;
35
- }
36
- Some ( & self . inner )
37
- }
38
-
39
- unsafe fn register_dtor ( & self ) {
40
- if !mem:: needs_drop :: < T > ( ) || self . dtor_registered . get ( ) {
41
- return
42
- }
43
-
44
- register_dtor ( self as * const _ as * mut u8 ,
45
- destroy_value :: < T > ) ;
46
- self . dtor_registered . set ( true ) ;
47
- }
48
- }
49
-
50
- pub unsafe fn register_dtor ( t : * mut u8 , dtor : unsafe extern fn ( * mut u8 ) ) {
51
- // The fallback implementation uses a vanilla OS-based TLS key to track
52
- // the list of destructors that need to be run for this thread. The key
53
- // then has its own destructor which runs all the other destructors.
54
- //
55
- // The destructor for DTORS is a little special in that it has a `while`
56
- // loop to continuously drain the list of registered destructors. It
57
- // *should* be the case that this loop always terminates because we
58
- // provide the guarantee that a TLS key cannot be set after it is
59
- // flagged for destruction.
60
- use crate :: sys_common:: thread_local as os;
61
-
62
- static DTORS : os:: StaticKey = os:: StaticKey :: new ( Some ( run_dtors) ) ;
63
- type List = Vec < ( * mut u8 , unsafe extern fn ( * mut u8 ) ) > ;
64
- if DTORS . get ( ) . is_null ( ) {
65
- let v: Box < List > = box Vec :: new ( ) ;
66
- DTORS . set ( Box :: into_raw ( v) as * mut u8 ) ;
67
- }
68
- let list: & mut List = & mut * ( DTORS . get ( ) as * mut List ) ;
69
- list. push ( ( t, dtor) ) ;
70
-
71
- unsafe extern fn run_dtors ( mut ptr : * mut u8 ) {
72
- while !ptr. is_null ( ) {
73
- let list: Box < List > = Box :: from_raw ( ptr as * mut List ) ;
74
- for ( ptr, dtor) in list. into_iter ( ) {
75
- dtor ( ptr) ;
76
- }
77
- ptr = DTORS . get ( ) ;
78
- DTORS . set ( ptr:: null_mut ( ) ) ;
79
- }
80
- }
81
- }
82
-
83
- pub unsafe extern fn destroy_value < T > ( ptr : * mut u8 ) {
84
- let ptr = ptr as * mut Key < T > ;
85
- // Right before we run the user destructor be sure to flag the
86
- // destructor as running for this thread so calls to `get` will return
87
- // `None`.
88
- ( * ptr) . dtor_running . set ( true ) ;
89
-
90
- // The macOS implementation of TLS apparently had an odd aspect to it
91
- // where the pointer we have may be overwritten while this destructor
92
- // is running. Specifically if a TLS destructor re-accesses TLS it may
93
- // trigger a re-initialization of all TLS variables, paving over at
94
- // least some destroyed ones with initial values.
95
- //
96
- // This means that if we drop a TLS value in place on macOS that we could
97
- // revert the value to its original state halfway through the
98
- // destructor, which would be bad!
99
- //
100
- // Hence, we use `ptr::read` on macOS (to move to a "safe" location)
101
- // instead of drop_in_place.
102
- if cfg ! ( target_os = "macos" ) {
103
- ptr:: read ( ( * ptr) . inner . get ( ) ) ;
104
- } else {
105
- ptr:: drop_in_place ( ( * ptr) . inner . get ( ) ) ;
106
- }
107
- }
4
+ pub use crate :: sys_common:: thread_local:: register_dtor_fallback as register_dtor;
0 commit comments