1- use super :: lazy:: LazyKeyInner ;
21use crate :: cell:: Cell ;
2+ use crate :: marker:: PhantomData ;
33use crate :: sys_common:: thread_local_key:: StaticKey as OsStaticKey ;
4- use crate :: { fmt , marker , panic, ptr} ;
4+ use crate :: { panic, ptr} ;
55
66#[ doc( hidden) ]
77#[ allow_internal_unstable( thread_local_internals) ]
@@ -10,38 +10,9 @@ use crate::{fmt, marker, panic, ptr};
1010#[ rustc_macro_transparency = "semitransparent" ]
1111pub macro thread_local_inner {
1212 // 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+ } ,
4516
4617 // used to generate the `LocalKey` value for `thread_local!`
4718 ( @key $t: ty, $init: expr) => {
@@ -85,78 +56,78 @@ pub macro thread_local_inner {
8556
8657/// Use a regular global static to store this key; the state provided will then be
8758 /// thread-local.
59+ #[ allow ( missing_debug_implementations) ]
8860pub struct Key <T > {
8961 // OS-TLS key that we'll use to key off.
9062 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 >>,
9864}
9965
10066unsafe impl < T > Sync for Key < T > { }
10167
10268struct Value < T : ' static > {
103- inner : LazyKeyInner < T > ,
69+ value : T ,
10470 key : & ' static Key < T > ,
10571}
10672
10773impl < T : ' static > Key < T > {
10874 #[ rustc_const_unstable( feature = "thread_local_internals" , issue = "none" ) ]
10975 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 }
11177 }
11278
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.
11584 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)
11786 let ptr = unsafe { self . os . get ( ) as * mut Value < T > } ;
11887 if ptr. addr ( ) > 1 {
11988 // SAFETY: the check ensured the pointer is safe (its destructor
12089 // 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) }
12495 }
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) }
12896 }
12997
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 > {
137108 if ptr. addr ( ) == 1 {
138109 // destructor is running
139110 return None ;
140111 }
141112
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+ }
156128
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 ) }
160131 }
161132}
162133
0 commit comments