Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c211a78

Browse files
committedDec 19, 2015
std: Use cfg(target_thread_local) in thread_local!
This transitions the standard library's `thread_local!` macro to use the freshly-added and gated `#[cfg(target_thread_local)]` attribute. This greatly simplifies the `#[cfg]` logic in play here, but requires that the standard library expose both the OS and ELF TLS implementation modules as unstable implementation details. The implementation details were shuffled around a bit but end up generally compiling to the same thing. Closes #26581 (this supersedes the need for the option) Closes #27057 (this also starts ignoring the option)
1 parent f8bbb60 commit c211a78

File tree

4 files changed

+50
-78
lines changed

4 files changed

+50
-78
lines changed
 

‎src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227
#![feature(borrow_state)]
228228
#![feature(box_syntax)]
229229
#![feature(cfg_target_vendor)]
230+
#![feature(cfg_target_thread_local)]
230231
#![feature(char_internals)]
231232
#![feature(clone_from_slice)]
232233
#![feature(collections)]

‎src/libstd/thread/local.rs

+44-76
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
use cell::UnsafeCell;
1616
use 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)]
12888
macro_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]
145105
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) => {{
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};

‎src/libstd/thread/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,10 @@ pub use self::local::{LocalKey, LocalKeyState};
191191
pub use self::scoped_tls::ScopedKey;
192192

193193
#[unstable(feature = "libstd_thread_internals", issue = "0")]
194-
#[doc(hidden)] pub use self::local::__KeyInner as __LocalKeyInner;
194+
#[cfg(target_thread_local)]
195+
#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner;
196+
#[unstable(feature = "libstd_thread_internals", issue = "0")]
197+
#[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner;
195198
#[unstable(feature = "libstd_thread_internals", issue = "0")]
196199
#[doc(hidden)] pub use self::scoped_tls::__KeyInner as __ScopedKeyInner;
197200

‎src/libsyntax/feature_gate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
238238
("type_ascription", "1.6.0", Some(23416), Active),
239239

240240
// Allows cfg(target_thread_local)
241-
("cfg_target_thread_local", "1.7.0", Some(26581), Active),
241+
("cfg_target_thread_local", "1.7.0", Some(29594), Active),
242242
];
243243
// (changing above list without updating src/doc/reference.md makes @cmr sad)
244244

0 commit comments

Comments
 (0)
Please sign in to comment.