1- use super :: lazy:: LazyKeyInner ;
2- use crate :: fmt;
1+ //! On some targets like wasm there's no threads, so no need to generate
2+ //! thread locals and we can instead just use plain statics!
3+
4+ use crate :: cell:: UnsafeCell ;
35
46#[ doc( hidden) ]
57#[ allow_internal_unstable( thread_local_internals) ]
@@ -9,23 +11,17 @@ use crate::fmt;
911pub macro thread_local_inner {
1012 // used to generate the `LocalKey` value for const-initialized thread locals
1113 ( @key $t: ty, const $init: expr) => { {
12- #[ inline] // see comments below
14+ const __INIT: $t = $init;
15+
16+ #[ inline]
1317 #[ deny( unsafe_op_in_unsafe_fn) ]
14- // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
15- #[ allow( static_mut_refs) ]
1618 unsafe fn __getit (
1719 _init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
1820 ) -> $crate:: option:: Option < & ' static $t> {
19- const INIT_EXPR : $t = $init;
20-
21- // wasm without atomics maps directly to `static mut`, and dtors
22- // aren't implemented because thread dtors aren't really a thing
23- // on wasm right now
24- //
25- // FIXME(#84224) this should come after the `target_thread_local`
26- // block.
27- static mut VAL : $t = INIT_EXPR ;
28- unsafe { $crate:: option:: Option :: Some ( & VAL ) }
21+ use $crate:: thread:: local_impl:: EagerStorage ;
22+
23+ static VAL : EagerStorage < $t> = EagerStorage { value : __INIT } ;
24+ $crate:: option:: Option :: Some ( & VAL . value )
2925 }
3026
3127 unsafe {
@@ -34,74 +30,83 @@ pub macro thread_local_inner {
3430 } } ,
3531
3632 // used to generate the `LocalKey` value for `thread_local!`
37- ( @key $t: ty, $init: expr) => {
38- {
39- #[ inline]
40- fn __init( ) -> $t { $init }
41- #[ inline]
42- unsafe fn __getit (
43- init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
44- ) -> $crate:: option:: Option < & ' static $t> {
45- static __KEY: $crate:: thread:: local_impl:: Key < $t> =
46- $crate:: thread:: local_impl:: Key :: new ( ) ;
47-
48- unsafe {
49- __KEY. get ( move || {
50- if let $crate:: option:: Option :: Some ( init) = init {
51- if let $crate:: option:: Option :: Some ( value) = init. take ( ) {
52- return value;
53- } else if $crate:: cfg!( debug_assertions) {
54- $crate:: unreachable!( "missing default value" ) ;
55- }
56- }
57- __init ( )
58- } )
59- }
60- }
61-
62- unsafe {
63- $crate:: thread:: LocalKey :: new ( __getit)
64- }
33+ ( @key $t: ty, $init: expr) => { {
34+ #[ inline]
35+ fn __init( ) -> $t { $init }
36+
37+ #[ inline]
38+ #[ deny( unsafe_op_in_unsafe_fn) ]
39+ unsafe fn __getit (
40+ init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
41+ ) -> $crate:: option:: Option < & ' static $t> {
42+ use $crate:: thread:: local_impl:: LazyStorage ;
43+
44+ static VAL : LazyStorage < $t> = LazyStorage :: new ( ) ;
45+ unsafe { $crate:: option:: Option :: Some ( VAL . get ( init, __init) ) }
6546 }
66- } ,
47+
48+ unsafe {
49+ $crate:: thread:: LocalKey :: new ( __getit)
50+ }
51+ } } ,
6752 ( $( #[ $attr: meta] ) * $vis: vis $name: ident, $t: ty, $( $init: tt) * ) => {
6853 $( #[ $attr] ) * $vis const $name: $crate:: thread:: LocalKey <$t> =
6954 $crate:: thread:: local_impl:: thread_local_inner!( @key $t, $( $init) * ) ;
7055 } ,
7156}
7257
73- /// On some targets like wasm there's no threads, so no need to generate
74- /// thread locals and we can instead just use plain statics!
75-
76- pub struct Key <T > {
77- inner: LazyKeyInner <T >,
58+ #[ allow ( missing_debug_implementations) ]
59+ pub struct EagerStorage <T > {
60+ pub value: T ,
7861}
7962
80- unsafe impl < T > Sync for Key < T > { }
63+ // SAFETY: the target doesn't have threads.
64+ unsafe impl < T > Sync for EagerStorage < T > { }
8165
82- impl < T > fmt:: Debug for Key < T > {
83- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
84- f. debug_struct ( "Key" ) . finish_non_exhaustive ( )
85- }
66+ #[ allow( missing_debug_implementations) ]
67+ pub struct LazyStorage < T > {
68+ value : UnsafeCell < Option < T > > ,
8669}
8770
88- impl < T > Key < T > {
89- pub const fn new ( ) -> Key < T > {
90- Key { inner : LazyKeyInner :: new ( ) }
71+ impl < T > LazyStorage < T > {
72+ pub const fn new ( ) -> LazyStorage < T > {
73+ LazyStorage { value : UnsafeCell :: new ( None ) }
9174 }
9275
93- pub unsafe fn get ( & self , init : impl FnOnce ( ) -> T ) -> Option < & ' static T > {
94- // SAFETY: The caller must ensure no reference is ever handed out to
95- // the inner cell nor mutable reference to the Option<T> inside said
96- // cell. This make it safe to hand a reference, though the lifetime
97- // of 'static is itself unsafe, making the get method unsafe.
98- let value = unsafe {
99- match self . inner . get ( ) {
100- Some ( ref value) => value,
101- None => self . inner . initialize ( init) ,
102- }
103- } ;
104-
105- Some ( value)
76+ /// Gets a reference to the contained value, initializing it if necessary.
77+ ///
78+ /// # Safety
79+ /// The returned reference may not be used after reentrant initialization has occurred.
80+ #[ inline]
81+ pub unsafe fn get (
82+ & ' static self ,
83+ i : Option < & mut Option < T > > ,
84+ f : impl FnOnce ( ) -> T ,
85+ ) -> & ' static T {
86+ let value = unsafe { & * self . value . get ( ) } ;
87+ match value {
88+ Some ( v) => v,
89+ None => self . initialize ( i, f) ,
90+ }
91+ }
92+
93+ #[ cold]
94+ unsafe fn initialize (
95+ & ' static self ,
96+ i : Option < & mut Option < T > > ,
97+ f : impl FnOnce ( ) -> T ,
98+ ) -> & ' static T {
99+ let value = i. and_then ( Option :: take) . unwrap_or_else ( f) ;
100+ // Destroy the old value, after updating the TLS variable as the
101+ // destructor might reference it.
102+ // FIXME(#110897): maybe panic on recursive initialization.
103+ unsafe {
104+ self . value . get ( ) . replace ( Some ( value) ) ;
105+ }
106+ // SAFETY: we just set this to `Some`.
107+ unsafe { ( * self . value . get ( ) ) . as_ref ( ) . unwrap_unchecked ( ) }
106108 }
107109}
110+
111+ // SAFETY: the target doesn't have threads.
112+ unsafe impl < T > Sync for LazyStorage < T > { }
0 commit comments