1
- use super :: lazy:: LazyKeyInner ;
2
1
use crate :: cell:: Cell ;
2
+ use crate :: marker:: PhantomData ;
3
3
use crate :: sys_common:: thread_local_key:: StaticKey as OsStaticKey ;
4
- use crate :: { fmt , marker , panic, ptr} ;
4
+ use crate :: { panic, ptr} ;
5
5
6
6
#[ doc( hidden) ]
7
7
#[ allow_internal_unstable( thread_local_internals) ]
@@ -10,38 +10,9 @@ use crate::{fmt, marker, panic, ptr};
10
10
#[ rustc_macro_transparency = "semitransparent" ]
11
11
pub macro thread_local_inner {
12
12
// used to generate the `LocalKey` value for const-initialized thread locals
13
- ( @key $t: ty, const $init: expr) => { {
14
- #[ inline]
15
- #[ deny( unsafe_op_in_unsafe_fn) ]
16
- unsafe fn __getit (
17
- _init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
18
- ) -> $crate:: option:: Option < & ' static $t> {
19
- const INIT_EXPR : $t = $init;
20
-
21
- // On platforms without `#[thread_local]` we fall back to the
22
- // same implementation as below for os thread locals.
23
- #[ inline]
24
- const fn __init ( ) -> $t { INIT_EXPR }
25
- static __KEY: $crate:: thread:: local_impl:: Key < $t> =
26
- $crate:: thread:: local_impl:: Key :: new ( ) ;
27
- unsafe {
28
- __KEY. get ( move || {
29
- if let $crate:: option:: Option :: Some ( init) = _init {
30
- if let $crate:: option:: Option :: Some ( value) = init. take ( ) {
31
- return value;
32
- } else if $crate:: cfg!( debug_assertions) {
33
- $crate:: unreachable!( "missing initial value" ) ;
34
- }
35
- }
36
- __init ( )
37
- } )
38
- }
39
- }
40
-
41
- unsafe {
42
- $crate:: thread:: LocalKey :: new ( __getit)
43
- }
44
- } } ,
13
+ ( @key $t: ty, const $init: expr) => {
14
+ $crate:: thread:: local_impl:: thread_local_inner!( @key $t, { const INIT_EXPR : $t = $init; INIT_EXPR } )
15
+ } ,
45
16
46
17
// used to generate the `LocalKey` value for `thread_local!`
47
18
( @key $t: ty, $init: expr) => {
@@ -85,78 +56,78 @@ pub macro thread_local_inner {
85
56
86
57
/// Use a regular global static to store this key; the state provided will then be
87
58
/// thread-local.
59
+ #[ allow ( missing_debug_implementations) ]
88
60
pub struct Key <T > {
89
61
// OS-TLS key that we'll use to key off.
90
62
os: OsStaticKey ,
91
- marker: marker:: PhantomData <Cell <T >>,
92
- }
93
-
94
- impl<T > fmt:: Debug for Key <T > {
95
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
96
- f. debug_struct ( "Key" ) . finish_non_exhaustive ( )
97
- }
63
+ marker: PhantomData <Cell <T >>,
98
64
}
99
65
100
66
unsafe impl < T > Sync for Key < T > { }
101
67
102
68
struct Value < T : ' static > {
103
- inner : LazyKeyInner < T > ,
69
+ value : T ,
104
70
key : & ' static Key < T > ,
105
71
}
106
72
107
73
impl < T : ' static > Key < T > {
108
74
#[ rustc_const_unstable( feature = "thread_local_internals" , issue = "none" ) ]
109
75
pub const fn new ( ) -> Key < T > {
110
- Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : marker :: PhantomData }
76
+ Key { os : OsStaticKey :: new ( Some ( destroy_value :: < T > ) ) , marker : PhantomData }
111
77
}
112
78
113
- /// It is a requirement for the caller to ensure that no mutable
114
- /// reference is active when this method is called.
79
+ /// Get the value associated with this key, initializating it if necessary.
80
+ ///
81
+ /// # Safety
82
+ /// * the returned reference must not be used after recursive initialization
83
+ /// or thread destruction occurs.
115
84
pub unsafe fn get ( & ' static self , init : impl FnOnce ( ) -> T ) -> Option < & ' static T > {
116
- // SAFETY: See the documentation for this method.
85
+ // SAFETY: (FIXME: get should actually be safe)
117
86
let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
118
87
if ptr. addr ( ) > 1 {
119
88
// SAFETY: the check ensured the pointer is safe (its destructor
120
89
// is not running) + it is coming from a trusted source (self).
121
- if let Some ( ref value) = unsafe { ( * ptr) . inner . get ( ) } {
122
- return Some ( value) ;
123
- }
90
+ unsafe { Some ( & ( * ptr) . value ) }
91
+ } else {
92
+ // SAFETY: At this point we are sure we have no value and so
93
+ // initializing (or trying to) is safe.
94
+ unsafe { self . try_initialize ( ptr, init) }
124
95
}
125
- // SAFETY: At this point we are sure we have no value and so
126
- // initializing (or trying to) is safe.
127
- unsafe { self . try_initialize ( init) }
128
96
}
129
97
130
- // `try_initialize` is only called once per os thread local variable,
131
- // except in corner cases where thread_local dtors reference other
132
- // thread_local's, or it is being recursively initialized.
133
- unsafe fn try_initialize ( & ' static self , init : impl FnOnce ( ) -> T ) -> Option < & ' static T > {
134
- // SAFETY: No mutable references are ever handed out meaning getting
135
- // the value is ok.
136
- let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
98
+ /// Initialize an empty TLS key.
99
+ ///
100
+ /// # Safety
101
+ /// * the same requirements as for `get` apply
102
+ /// * `ptr` must be the current value of the key, and must be either null or the sentinel value
103
+ unsafe fn try_initialize (
104
+ & ' static self ,
105
+ ptr : * mut Value < T > ,
106
+ init : impl FnOnce ( ) -> T ,
107
+ ) -> Option < & ' static T > {
137
108
if ptr. addr ( ) == 1 {
138
109
// destructor is running
139
110
return None ;
140
111
}
141
112
142
- let ptr = if ptr. is_null ( ) {
143
- // If the lookup returned null, we haven't initialized our own
144
- // local copy, so do that now.
145
- let ptr = Box :: into_raw ( Box :: new ( Value { inner : LazyKeyInner :: new ( ) , key : self } ) ) ;
146
- // SAFETY: At this point we are sure there is no value inside
147
- // ptr so setting it will not affect anyone else.
148
- unsafe {
149
- self . os . set ( ptr as * mut u8 ) ;
150
- }
151
- ptr
152
- } else {
153
- // recursive initialization
154
- ptr
155
- } ;
113
+ let ptr = Box :: into_raw ( Box :: new ( Value { value : init ( ) , key : self } ) ) ;
114
+ // SAFETY: (FIXME: get should actually be safe)
115
+ let old = unsafe { self . os . get ( ) as * mut Value < T > } ;
116
+ // SAFETY: `ptr` is a correct pointer that can be destroyed by the key destructor.
117
+ unsafe {
118
+ self . os . set ( ptr as * mut u8 ) ;
119
+ }
120
+ if !old. is_null ( ) {
121
+ // If the variable was recursively initialized, drop the old value.
122
+ // SAFETY: We cannot be inside a `LocalKey::with` scope, as the
123
+ // initializer has already returned and the next scope only starts
124
+ // after we return the pointer. Therefore, there can be no references
125
+ // to the old value.
126
+ drop ( unsafe { Box :: from_raw ( old) } ) ;
127
+ }
156
128
157
- // SAFETY: ptr has been ensured as non-NUL just above an so can be
158
- // dereferenced safely.
159
- unsafe { Some ( ( * ptr) . inner . initialize ( init) ) }
129
+ // SAFETY: We just created this value above.
130
+ unsafe { Some ( & ( * ptr) . value ) }
160
131
}
161
132
}
162
133
0 commit comments