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,22 +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) ]
1418 unsafe fn __getit (
1519 _init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
1620 ) -> $crate:: option:: Option < & ' static $t> {
17- const INIT_EXPR : $t = $init;
18-
19- // wasm without atomics maps directly to `static mut`, and dtors
20- // aren't implemented because thread dtors aren't really a thing
21- // on wasm right now
22- //
23- // FIXME(#84224) this should come after the `target_thread_local`
24- // block.
25- static mut VAL : $t = INIT_EXPR ;
26- // SAFETY: we only ever create shared references, so there's no mutable aliasing.
27- unsafe { $crate:: option:: Option :: Some ( & * $crate:: ptr:: addr_of!( VAL ) ) }
21+ use $crate:: thread:: local_impl:: EagerStorage ;
22+
23+ static VAL : EagerStorage < $t> = EagerStorage { value : __INIT } ;
24+ $crate:: option:: Option :: Some ( & VAL . value )
2825 }
2926
3027 unsafe {
@@ -33,74 +30,83 @@ pub macro thread_local_inner {
3330 } } ,
3431
3532 // used to generate the `LocalKey` value for `thread_local!`
36- ( @key $t: ty, $init: expr) => {
37- {
38- #[ inline]
39- fn __init( ) -> $t { $init }
40- #[ inline]
41- unsafe fn __getit (
42- init : $crate:: option:: Option < & mut $crate:: option:: Option < $t> > ,
43- ) -> $crate:: option:: Option < & ' static $t> {
44- static __KEY: $crate:: thread:: local_impl:: Key < $t> =
45- $crate:: thread:: local_impl:: Key :: new ( ) ;
46-
47- unsafe {
48- __KEY. get ( move || {
49- if let $crate:: option:: Option :: Some ( init) = init {
50- if let $crate:: option:: Option :: Some ( value) = init. take ( ) {
51- return value;
52- } else if $crate:: cfg!( debug_assertions) {
53- $crate:: unreachable!( "missing default value" ) ;
54- }
55- }
56- __init ( )
57- } )
58- }
59- }
60-
61- unsafe {
62- $crate:: thread:: LocalKey :: new ( __getit)
63- }
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) ) }
6446 }
65- } ,
47+
48+ unsafe {
49+ $crate:: thread:: LocalKey :: new ( __getit)
50+ }
51+ } } ,
6652 ( $( #[ $attr: meta] ) * $vis: vis $name: ident, $t: ty, $( $init: tt) * ) => {
6753 $( #[ $attr] ) * $vis const $name: $crate:: thread:: LocalKey <$t> =
6854 $crate:: thread:: local_impl:: thread_local_inner!( @key $t, $( $init) * ) ;
6955 } ,
7056}
7157
72- /// On some targets like wasm there's no threads, so no need to generate
73- /// thread locals and we can instead just use plain statics!
74-
75- pub struct Key <T > {
76- inner: LazyKeyInner <T >,
58+ #[ allow ( missing_debug_implementations) ]
59+ pub struct EagerStorage <T > {
60+ pub value: T ,
7761}
7862
79- unsafe impl < T > Sync for Key < T > { }
63+ // SAFETY: the target doesn't have threads.
64+ unsafe impl < T > Sync for EagerStorage < T > { }
8065
81- impl < T > fmt:: Debug for Key < T > {
82- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
83- f. debug_struct ( "Key" ) . finish_non_exhaustive ( )
84- }
66+ #[ allow( missing_debug_implementations) ]
67+ pub struct LazyStorage < T > {
68+ value : UnsafeCell < Option < T > > ,
8569}
8670
87- impl < T > Key < T > {
88- pub const fn new ( ) -> Key < T > {
89- Key { inner : LazyKeyInner :: new ( ) }
71+ impl < T > LazyStorage < T > {
72+ pub const fn new ( ) -> LazyStorage < T > {
73+ LazyStorage { value : UnsafeCell :: new ( None ) }
9074 }
9175
92- pub unsafe fn get ( & self , init : impl FnOnce ( ) -> T ) -> Option < & ' static T > {
93- // SAFETY: The caller must ensure no reference is ever handed out to
94- // the inner cell nor mutable reference to the Option<T> inside said
95- // cell. This make it safe to hand a reference, though the lifetime
96- // of 'static is itself unsafe, making the get method unsafe.
97- let value = unsafe {
98- match self . inner . get ( ) {
99- Some ( ref value) => value,
100- None => self . inner . initialize ( init) ,
101- }
102- } ;
103-
104- 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 ( ) }
105108 }
106109}
110+
111+ // SAFETY: the target doesn't have threads.
112+ unsafe impl < T > Sync for LazyStorage < T > { }
0 commit comments