15
15
use cell:: UnsafeCell ;
16
16
use mem;
17
17
18
- // Sure wish we had macro hygiene, no?
19
- #[ doc( hidden) ]
20
- pub use self :: imp:: Key as __KeyInner;
21
-
22
18
/// A thread local storage key which owns its contents.
23
19
///
24
20
/// This key uses the fastest possible implementation available to it for the
@@ -61,78 +57,42 @@ pub use self::imp::Key as __KeyInner;
61
57
/// });
62
58
/// ```
63
59
#[ 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`!
70
70
//
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 > > > ,
74
76
75
77
// initialization routine to invoke to create a value
76
78
init : fn ( ) -> T ,
77
79
}
78
80
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
-
99
81
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
100
82
///
101
83
/// See [LocalKey documentation](thread/struct.LocalKey.html) for more
102
84
/// information.
103
85
#[ macro_export]
104
86
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
105
87
#[ 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) ]
128
88
macro_rules! thread_local {
129
89
( static $name: ident: $t: ty = $init: expr) => (
130
90
static $name: $crate:: thread:: LocalKey <$t> =
131
- __thread_local_inner!( $t, $init, # [ ] ) ;
91
+ __thread_local_inner!( $t, $init) ;
132
92
) ;
133
93
( pub static $name: ident: $t: ty = $init: expr) => (
134
94
pub static $name: $crate:: thread:: LocalKey <$t> =
135
- __thread_local_inner!( $t, $init, # [ ] ) ;
95
+ __thread_local_inner!( $t, $init) ;
136
96
) ;
137
97
}
138
98
@@ -143,12 +103,25 @@ macro_rules! thread_local {
143
103
#[ macro_export]
144
104
#[ allow_internal_unstable]
145
105
macro_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) => { {
150
107
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
+
152
125
$crate:: thread:: LocalKey :: new( __getit, __init)
153
126
} }
154
127
}
@@ -190,11 +163,11 @@ impl<T: 'static> LocalKey<T> {
190
163
#[ unstable( feature = "thread_local_internals" ,
191
164
reason = "recently added to create a key" ,
192
165
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 > > > ,
194
167
init : fn ( ) -> T ) -> LocalKey < T > {
195
168
LocalKey {
196
169
inner : inner,
197
- init : init
170
+ init : init,
198
171
}
199
172
}
200
173
@@ -211,10 +184,10 @@ impl<T: 'static> LocalKey<T> {
211
184
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
212
185
pub fn with < F , R > ( & ' static self , f : F ) -> R
213
186
where F : FnOnce ( & T ) -> R {
214
- let slot = ( self . inner ) ( ) ;
215
187
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") ;
218
191
f ( match * slot. get ( ) {
219
192
Some ( ref inner) => inner,
220
193
None => self . init ( slot) ,
@@ -270,7 +243,7 @@ impl<T: 'static> LocalKey<T> {
270
243
issue = "27716" ) ]
271
244
pub fn state ( & ' static self ) -> LocalKeyState {
272
245
unsafe {
273
- match ( self . inner ) ( ) . get ( ) {
246
+ match ( self . inner ) ( ) {
274
247
Some ( cell) => {
275
248
match * cell. get ( ) {
276
249
Some ( ..) => LocalKeyState :: Valid ,
@@ -283,11 +256,9 @@ impl<T: 'static> LocalKey<T> {
283
256
}
284
257
}
285
258
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) ]
289
260
#[ doc( hidden) ]
290
- mod imp {
261
+ pub mod elf {
291
262
use cell:: { Cell , UnsafeCell } ;
292
263
use intrinsics;
293
264
use ptr;
@@ -431,11 +402,8 @@ mod imp {
431
402
}
432
403
}
433
404
434
- #[ cfg( any( not( any( target_os = "macos" , target_os = "linux" ) ) ,
435
- target_arch = "aarch64" ,
436
- no_elf_tls) ) ]
437
405
#[ doc( hidden) ]
438
- mod imp {
406
+ pub mod os {
439
407
use prelude:: v1:: * ;
440
408
441
409
use cell:: { Cell , UnsafeCell } ;
0 commit comments