1515use cell:: UnsafeCell ;
1616use mem;
1717
18- // Sure wish we had macro hygiene, no?
19- #[ doc( hidden) ]
20- pub use self :: imp:: Key as __KeyInner;
21-
2218/// A thread local storage key which owns its contents.
2319///
2420/// This key uses the fastest possible implementation available to it for the
@@ -61,78 +57,42 @@ pub use self::imp::Key as __KeyInner;
6157/// });
6258/// ```
6359#[ stable( feature = "rust1" , since = "1.0.0" ) ]
64- pub struct LocalKey < T : ' static > {
65- // The key itself may be tagged with #[thread_local], and this `Key` is
66- // stored as a `static`, and it's not valid for a static to reference the
67- // address of another thread_local static. For this reason we kinda wonkily
68- // work around this by generating a shim function which will give us the
69- // address of the inner TLS key at runtime.
60+ pub struct LocalKey < T : ' static > {
61+ // This outer `LocalKey<T>` type is what's going to be stored in statics,
62+ // but actual data inside will sometimes be tagged with #[thread_local].
63+ // It's not valid for a true static to reference a #[thread_local] static,
64+ // so we get around that by exposing an accessor through a layer of function
65+ // indirection (this thunk).
66+ //
67+ // Note that the thunk is itself unsafe because the returned lifetime of the
68+ // slot where data lives, `'static`, is not actually valid. The lifetime
69+ // here is actually `'thread`!
7070 //
71- // This is trivially devirtualizable by LLVM because we never store anything
72- // to this field and rustc can declare the `static` as constant as well.
73- inner : fn ( ) -> & ' static __KeyInner < T > ,
71+ // Although this is an extra layer of indirection, it should in theory be
72+ // trivially devirtualizable by LLVM because the value of `inner` never
73+ // changes and the constant should be readonly within a crate. This mainly
74+ // only runs into problems when TLS statics are exported across crates.
75+ inner : unsafe fn ( ) -> Option < & ' static UnsafeCell < Option < T > > > ,
7476
7577 // initialization routine to invoke to create a value
7678 init : fn ( ) -> T ,
7779}
7880
79- // Macro pain #4586:
80- //
81- // When cross compiling, rustc will load plugins and macros from the *host*
82- // platform before search for macros from the target platform. This is primarily
83- // done to detect, for example, plugins. Ideally the macro below would be
84- // defined once per module below, but unfortunately this means we have the
85- // following situation:
86- //
87- // 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro
88- // will inject #[thread_local] statics.
89- // 2. We then try to compile a program for arm-linux-androideabi
90- // 3. The compiler has a host of linux and a target of android, so it loads
91- // macros from the *linux* libstd.
92- // 4. The macro generates a #[thread_local] field, but the android libstd does
93- // not use #[thread_local]
94- // 5. Compile error about structs with wrong fields.
95- //
96- // To get around this, we're forced to inject the #[cfg] logic into the macro
97- // itself. Woohoo.
98-
9981/// Declare a new thread local storage key of type `std::thread::LocalKey`.
10082///
10183/// See [LocalKey documentation](thread/struct.LocalKey.html) for more
10284/// information.
10385#[ macro_export]
10486#[ stable( feature = "rust1" , since = "1.0.0" ) ]
10587#[ allow_internal_unstable]
106- #[ cfg( not( no_elf_tls) ) ]
107- macro_rules! thread_local {
108- ( static $name: ident: $t: ty = $init: expr) => (
109- static $name: $crate:: thread:: LocalKey <$t> =
110- __thread_local_inner!( $t, $init,
111- #[ cfg_attr( all( any( target_os = "macos" , target_os = "linux" ) ,
112- not( target_arch = "aarch64" ) ) ,
113- thread_local) ] ) ;
114- ) ;
115- ( pub static $name: ident: $t: ty = $init: expr) => (
116- pub static $name: $crate:: thread:: LocalKey <$t> =
117- __thread_local_inner!( $t, $init,
118- #[ cfg_attr( all( any( target_os = "macos" , target_os = "linux" ) ,
119- not( target_arch = "aarch64" ) ) ,
120- thread_local) ] ) ;
121- ) ;
122- }
123-
124- #[ macro_export]
125- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
126- #[ allow_internal_unstable]
127- #[ cfg( no_elf_tls) ]
12888macro_rules! thread_local {
12989 ( static $name: ident: $t: ty = $init: expr) => (
13090 static $name: $crate:: thread:: LocalKey <$t> =
131- __thread_local_inner!( $t, $init, # [ ] ) ;
91+ __thread_local_inner!( $t, $init) ;
13292 ) ;
13393 ( pub static $name: ident: $t: ty = $init: expr) => (
13494 pub static $name: $crate:: thread:: LocalKey <$t> =
135- __thread_local_inner!( $t, $init, # [ ] ) ;
95+ __thread_local_inner!( $t, $init) ;
13696 ) ;
13797}
13898
@@ -143,12 +103,25 @@ macro_rules! thread_local {
143103#[ macro_export]
144104#[ allow_internal_unstable]
145105macro_rules! __thread_local_inner {
146- ( $t: ty, $init: expr, #[ $( $attr: meta) ,* ] ) => { {
147- $( #[ $attr] ) *
148- static __KEY: $crate:: thread:: __LocalKeyInner<$t> =
149- $crate:: thread:: __LocalKeyInner:: new( ) ;
106+ ( $t: ty, $init: expr) => { {
150107 fn __init( ) -> $t { $init }
151- fn __getit( ) -> & ' static $crate:: thread:: __LocalKeyInner<$t> { & __KEY }
108+
109+ unsafe fn __getit( ) -> $crate:: option:: Option <
110+ & ' static $crate:: cell:: UnsafeCell <
111+ $crate:: option:: Option <$t>>>
112+ {
113+ #[ thread_local]
114+ #[ cfg( target_thread_local) ]
115+ static __KEY: $crate:: thread:: __ElfLocalKeyInner<$t> =
116+ $crate:: thread:: __ElfLocalKeyInner:: new( ) ;
117+
118+ #[ cfg( not( target_thread_local) ) ]
119+ static __KEY: $crate:: thread:: __OsLocalKeyInner<$t> =
120+ $crate:: thread:: __OsLocalKeyInner:: new( ) ;
121+
122+ __KEY. get( )
123+ }
124+
152125 $crate:: thread:: LocalKey :: new( __getit, __init)
153126 } }
154127}
@@ -190,11 +163,11 @@ impl<T: 'static> LocalKey<T> {
190163 #[ unstable( feature = "thread_local_internals" ,
191164 reason = "recently added to create a key" ,
192165 issue = "0" ) ]
193- pub const fn new ( inner : fn ( ) -> & ' static __KeyInner < T > ,
166+ pub const fn new ( inner : unsafe fn ( ) -> Option < & ' static UnsafeCell < Option < T > > > ,
194167 init : fn ( ) -> T ) -> LocalKey < T > {
195168 LocalKey {
196169 inner : inner,
197- init : init
170+ init : init,
198171 }
199172 }
200173
@@ -211,10 +184,10 @@ impl<T: 'static> LocalKey<T> {
211184 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
212185 pub fn with < F , R > ( & ' static self , f : F ) -> R
213186 where F : FnOnce ( & T ) -> R {
214- let slot = ( self . inner ) ( ) ;
215187 unsafe {
216- let slot = slot. get ( ) . expect ( "cannot access a TLS value during or \
217- after it is destroyed") ;
188+ let slot = ( self . inner ) ( ) ;
189+ let slot = slot. expect ( "cannot access a TLS value during or \
190+ after it is destroyed") ;
218191 f ( match * slot. get ( ) {
219192 Some ( ref inner) => inner,
220193 None => self . init ( slot) ,
@@ -270,7 +243,7 @@ impl<T: 'static> LocalKey<T> {
270243 issue = "27716" ) ]
271244 pub fn state ( & ' static self ) -> LocalKeyState {
272245 unsafe {
273- match ( self . inner ) ( ) . get ( ) {
246+ match ( self . inner ) ( ) {
274247 Some ( cell) => {
275248 match * cell. get ( ) {
276249 Some ( ..) => LocalKeyState :: Valid ,
@@ -283,11 +256,9 @@ impl<T: 'static> LocalKey<T> {
283256 }
284257}
285258
286- #[ cfg( all( any( target_os = "macos" , target_os = "linux" ) ,
287- not( target_arch = "aarch64" ) ,
288- not( no_elf_tls) ) ) ]
259+ #[ cfg( target_thread_local) ]
289260#[ doc( hidden) ]
290- mod imp {
261+ pub mod elf {
291262 use cell:: { Cell , UnsafeCell } ;
292263 use intrinsics;
293264 use ptr;
@@ -431,11 +402,8 @@ mod imp {
431402 }
432403}
433404
434- #[ cfg( any( not( any( target_os = "macos" , target_os = "linux" ) ) ,
435- target_arch = "aarch64" ,
436- no_elf_tls) ) ]
437405#[ doc( hidden) ]
438- mod imp {
406+ pub mod os {
439407 use prelude:: v1:: * ;
440408
441409 use cell:: { Cell , UnsafeCell } ;
0 commit comments