Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cb9aa8c

Browse files
committedApr 26, 2023
Auto merge of rust-lang#110861 - m-ou-se:thread-local-restructure, r=workingjubilee
Restructure and rename std thread_local internals to make it less of a maze Every time I try to work on std's thread local internals, it feels like I'm trying to navigate a confusing maze made of macros, deeply nested modules, and types with multiple names/aliases. Time to clean it up a bit. This PR: - Exports `Key` with its own name (`Key`), instead of `__LocalKeyInner` - Uses `pub macro` to put `__thread_local_inner` into a (unstable, hidden) module, removing `#[macro_export]`, removing it from the crate root. - Removes the `__` from `__thread_local_inner`. - Removes a few unnecessary `allow_internal_unstable` features from the macros - Removes the `libstd_thread_internals` feature. (Merged with `thread_local_internals`.) - And removes it from the unstable book - Gets rid of the deeply nested modules for the `Key` definitions (`mod fast` / `mod os` / `mod statik`). - Turns a `#[cfg]` mess into a single `cfg_if`, now that there's no `#[macro_export]` anymore that breaks with `cfg_if`. - Simplifies the `cfg_if` conditions to not repeat the conditions. - Removes useless `normalize-stderr-test`, which were left over from when the `Key` types had different names on different platforms. - Removes a seemingly unnecessary `realstd` re-export on `cfg(test)`. This PR changes nothing about the thread local implementation. That's for a later PR. (Which should hopefully be easier once all this stuff is a bit cleaned up.)
2 parents 1c42cb4 + 12fee7b commit cb9aa8c

File tree

12 files changed

+293
-328
lines changed

12 files changed

+293
-328
lines changed
 
Lines changed: 124 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
use super::lazy::LazyKeyInner;
2+
use crate::cell::Cell;
3+
use crate::sys::thread_local_dtor::register_dtor;
4+
use crate::{fmt, mem, panic};
5+
16
#[doc(hidden)]
2-
#[macro_export]
3-
#[allow_internal_unstable(
4-
thread_local_internals,
5-
cfg_target_thread_local,
6-
thread_local,
7-
libstd_thread_internals
8-
)]
7+
#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
98
#[allow_internal_unsafe]
10-
macro_rules! __thread_local_inner {
9+
#[unstable(feature = "thread_local_internals", issue = "none")]
10+
#[rustc_macro_transparency = "semitransparent"]
11+
pub macro thread_local_inner {
1112
// used to generate the `LocalKey` value for const-initialized thread locals
1213
(@key $t:ty, const $init:expr) => {{
1314
#[cfg_attr(not(bootstrap), inline)]
@@ -49,7 +50,7 @@ macro_rules! __thread_local_inner {
4950
// 0 == we haven't registered a destructor, so do
5051
// so now.
5152
0 => {
52-
$crate::thread::__LocalKeyInner::<$t>::register_dtor(
53+
$crate::thread::local_impl::Key::<$t>::register_dtor(
5354
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
5455
destroy,
5556
);
@@ -69,7 +70,7 @@ macro_rules! __thread_local_inner {
6970
unsafe {
7071
$crate::thread::LocalKey::new(__getit)
7172
}
72-
}};
73+
}},
7374

7475
// used to generate the `LocalKey` value for `thread_local!`
7576
(@key $t:ty, $init:expr) => {
@@ -82,8 +83,8 @@ macro_rules! __thread_local_inner {
8283
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
8384
) -> $crate::option::Option<&'static $t> {
8485
#[thread_local]
85-
static __KEY: $crate::thread::__LocalKeyInner<$t> =
86-
$crate::thread::__LocalKeyInner::<$t>::new();
86+
static __KEY: $crate::thread::local_impl::Key<$t> =
87+
$crate::thread::local_impl::Key::<$t>::new();
8788

8889
// FIXME: remove the #[allow(...)] marker when macros don't
8990
// raise warning for missing/extraneous unsafe blocks anymore.
@@ -107,148 +108,140 @@ macro_rules! __thread_local_inner {
107108
$crate::thread::LocalKey::new(__getit)
108109
}
109110
}
110-
};
111+
},
111112
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
112113
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
113-
$crate::__thread_local_inner!(@key $t, $($init)*);
114-
}
114+
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
115+
},
115116
}
116117

117-
#[doc(hidden)]
118-
pub mod fast {
119-
use super::super::lazy::LazyKeyInner;
120-
use crate::cell::Cell;
121-
use crate::sys::thread_local_dtor::register_dtor;
122-
use crate::{fmt, mem, panic};
123-
124-
#[derive(Copy, Clone)]
125-
enum DtorState {
126-
Unregistered,
127-
Registered,
128-
RunningOrHasRun,
129-
}
118+
#[derive(Copy, Clone)]
119+
enum DtorState {
120+
Unregistered,
121+
Registered,
122+
RunningOrHasRun,
123+
}
130124

131-
// This data structure has been carefully constructed so that the fast path
132-
// only contains one branch on x86. That optimization is necessary to avoid
133-
// duplicated tls lookups on OSX.
125+
// This data structure has been carefully constructed so that the fast path
126+
// only contains one branch on x86. That optimization is necessary to avoid
127+
// duplicated tls lookups on OSX.
128+
//
129+
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
130+
pub struct Key<T> {
131+
// If `LazyKeyInner::get` returns `None`, that indicates either:
132+
// * The value has never been initialized
133+
// * The value is being recursively initialized
134+
// * The value has already been destroyed or is being destroyed
135+
// To determine which kind of `None`, check `dtor_state`.
134136
//
135-
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
136-
pub struct Key<T> {
137-
// If `LazyKeyInner::get` returns `None`, that indicates either:
138-
// * The value has never been initialized
139-
// * The value is being recursively initialized
140-
// * The value has already been destroyed or is being destroyed
141-
// To determine which kind of `None`, check `dtor_state`.
142-
//
143-
// This is very optimizer friendly for the fast path - initialized but
144-
// not yet dropped.
145-
inner: LazyKeyInner<T>,
137+
// This is very optimizer friendly for the fast path - initialized but
138+
// not yet dropped.
139+
inner: LazyKeyInner<T>,
146140

147-
// Metadata to keep track of the state of the destructor. Remember that
148-
// this variable is thread-local, not global.
149-
dtor_state: Cell<DtorState>,
150-
}
141+
// Metadata to keep track of the state of the destructor. Remember that
142+
// this variable is thread-local, not global.
143+
dtor_state: Cell<DtorState>,
144+
}
151145

152-
impl<T> fmt::Debug for Key<T> {
153-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154-
f.debug_struct("Key").finish_non_exhaustive()
155-
}
146+
impl<T> fmt::Debug for Key<T> {
147+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148+
f.debug_struct("Key").finish_non_exhaustive()
156149
}
150+
}
157151

158-
impl<T> Key<T> {
159-
pub const fn new() -> Key<T> {
160-
Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
161-
}
152+
impl<T> Key<T> {
153+
pub const fn new() -> Key<T> {
154+
Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
155+
}
162156

163-
// note that this is just a publicly-callable function only for the
164-
// const-initialized form of thread locals, basically a way to call the
165-
// free `register_dtor` function defined elsewhere in std.
166-
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
167-
unsafe {
168-
register_dtor(a, dtor);
169-
}
157+
// note that this is just a publicly-callable function only for the
158+
// const-initialized form of thread locals, basically a way to call the
159+
// free `register_dtor` function defined elsewhere in std.
160+
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
161+
unsafe {
162+
register_dtor(a, dtor);
170163
}
164+
}
171165

172-
pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
173-
// SAFETY: See the definitions of `LazyKeyInner::get` and
174-
// `try_initialize` for more information.
175-
//
176-
// The caller must ensure no mutable references are ever active to
177-
// the inner cell or the inner T when this is called.
178-
// The `try_initialize` is dependant on the passed `init` function
179-
// for this.
180-
unsafe {
181-
match self.inner.get() {
182-
Some(val) => Some(val),
183-
None => self.try_initialize(init),
184-
}
166+
pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
167+
// SAFETY: See the definitions of `LazyKeyInner::get` and
168+
// `try_initialize` for more information.
169+
//
170+
// The caller must ensure no mutable references are ever active to
171+
// the inner cell or the inner T when this is called.
172+
// The `try_initialize` is dependant on the passed `init` function
173+
// for this.
174+
unsafe {
175+
match self.inner.get() {
176+
Some(val) => Some(val),
177+
None => self.try_initialize(init),
185178
}
186179
}
180+
}
187181

188-
// `try_initialize` is only called once per fast thread local variable,
189-
// except in corner cases where thread_local dtors reference other
190-
// thread_local's, or it is being recursively initialized.
191-
//
192-
// Macos: Inlining this function can cause two `tlv_get_addr` calls to
193-
// be performed for every call to `Key::get`.
194-
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
195-
#[inline(never)]
196-
unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
182+
// `try_initialize` is only called once per fast thread local variable,
183+
// except in corner cases where thread_local dtors reference other
184+
// thread_local's, or it is being recursively initialized.
185+
//
186+
// Macos: Inlining this function can cause two `tlv_get_addr` calls to
187+
// be performed for every call to `Key::get`.
188+
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
189+
#[inline(never)]
190+
unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
191+
// SAFETY: See comment above (this function doc).
192+
if !mem::needs_drop::<T>() || unsafe { self.try_register_dtor() } {
197193
// SAFETY: See comment above (this function doc).
198-
if !mem::needs_drop::<T>() || unsafe { self.try_register_dtor() } {
199-
// SAFETY: See comment above (this function doc).
200-
Some(unsafe { self.inner.initialize(init) })
201-
} else {
202-
None
203-
}
194+
Some(unsafe { self.inner.initialize(init) })
195+
} else {
196+
None
204197
}
198+
}
205199

206-
// `try_register_dtor` is only called once per fast thread local
207-
// variable, except in corner cases where thread_local dtors reference
208-
// other thread_local's, or it is being recursively initialized.
209-
unsafe fn try_register_dtor(&self) -> bool {
210-
match self.dtor_state.get() {
211-
DtorState::Unregistered => {
212-
// SAFETY: dtor registration happens before initialization.
213-
// Passing `self` as a pointer while using `destroy_value<T>`
214-
// is safe because the function will build a pointer to a
215-
// Key<T>, which is the type of self and so find the correct
216-
// size.
217-
unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::<T>) };
218-
self.dtor_state.set(DtorState::Registered);
219-
true
220-
}
221-
DtorState::Registered => {
222-
// recursively initialized
223-
true
224-
}
225-
DtorState::RunningOrHasRun => false,
200+
// `try_register_dtor` is only called once per fast thread local
201+
// variable, except in corner cases where thread_local dtors reference
202+
// other thread_local's, or it is being recursively initialized.
203+
unsafe fn try_register_dtor(&self) -> bool {
204+
match self.dtor_state.get() {
205+
DtorState::Unregistered => {
206+
// SAFETY: dtor registration happens before initialization.
207+
// Passing `self` as a pointer while using `destroy_value<T>`
208+
// is safe because the function will build a pointer to a
209+
// Key<T>, which is the type of self and so find the correct
210+
// size.
211+
unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::<T>) };
212+
self.dtor_state.set(DtorState::Registered);
213+
true
226214
}
215+
DtorState::Registered => {
216+
// recursively initialized
217+
true
218+
}
219+
DtorState::RunningOrHasRun => false,
227220
}
228221
}
222+
}
229223

230-
unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
231-
let ptr = ptr as *mut Key<T>;
224+
unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
225+
let ptr = ptr as *mut Key<T>;
232226

233-
// SAFETY:
234-
//
235-
// The pointer `ptr` has been built just above and comes from
236-
// `try_register_dtor` where it is originally a Key<T> coming from `self`,
237-
// making it non-NUL and of the correct type.
238-
//
239-
// Right before we run the user destructor be sure to set the
240-
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
241-
// causes future calls to `get` to run `try_initialize_drop` again,
242-
// which will now fail, and return `None`.
243-
//
244-
// Wrap the call in a catch to ensure unwinding is caught in the event
245-
// a panic takes place in a destructor.
246-
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
247-
let value = (*ptr).inner.take();
248-
(*ptr).dtor_state.set(DtorState::RunningOrHasRun);
249-
drop(value);
250-
})) {
251-
rtabort!("thread local panicked on drop");
252-
}
227+
// SAFETY:
228+
//
229+
// The pointer `ptr` has been built just above and comes from
230+
// `try_register_dtor` where it is originally a Key<T> coming from `self`,
231+
// making it non-NUL and of the correct type.
232+
//
233+
// Right before we run the user destructor be sure to set the
234+
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
235+
// causes future calls to `get` to run `try_initialize_drop` again,
236+
// which will now fail, and return `None`.
237+
//
238+
// Wrap the call in a catch to ensure unwinding is caught in the event
239+
// a panic takes place in a destructor.
240+
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
241+
let value = (*ptr).inner.take();
242+
(*ptr).dtor_state.set(DtorState::RunningOrHasRun);
243+
drop(value);
244+
})) {
245+
rtabort!("thread local panicked on drop");
253246
}
254247
}

‎library/std/src/sys/common/thread_local/mod.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,24 @@
1-
//! The following module declarations are outside cfg_if because the internal
2-
//! `__thread_local_internal` macro does not seem to be exported properly when using cfg_if
31
#![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
42

5-
#[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics")))))]
6-
mod fast_local;
7-
#[cfg(all(
8-
not(target_thread_local),
9-
not(all(target_family = "wasm", not(target_feature = "atomics")))
10-
))]
11-
mod os_local;
12-
#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
13-
mod static_local;
14-
15-
#[cfg(not(test))]
163
cfg_if::cfg_if! {
174
if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
185
#[doc(hidden)]
19-
pub use static_local::statik::Key;
20-
} else if #[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics")))))] {
6+
mod static_local;
7+
#[doc(hidden)]
8+
pub use static_local::{Key, thread_local_inner};
9+
} else if #[cfg(all(target_thread_local))] {
10+
#[doc(hidden)]
11+
mod fast_local;
2112
#[doc(hidden)]
22-
pub use fast_local::fast::Key;
23-
} else if #[cfg(all(not(target_thread_local), not(all(target_family = "wasm", not(target_feature = "atomics")))))] {
13+
pub use fast_local::{Key, thread_local_inner};
14+
} else {
2415
#[doc(hidden)]
25-
pub use os_local::os::Key;
16+
mod os_local;
17+
#[doc(hidden)]
18+
pub use os_local::{Key, thread_local_inner};
2619
}
2720
}
2821

29-
#[doc(hidden)]
30-
#[cfg(test)]
31-
pub use realstd::thread::__LocalKeyInner as Key;
32-
3322
mod lazy {
3423
use crate::cell::UnsafeCell;
3524
use crate::hint;
Lines changed: 102 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
use super::lazy::LazyKeyInner;
2+
use crate::cell::Cell;
3+
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
4+
use crate::{fmt, marker, panic, ptr};
5+
16
#[doc(hidden)]
2-
#[macro_export]
3-
#[allow_internal_unstable(
4-
thread_local_internals,
5-
cfg_target_thread_local,
6-
thread_local,
7-
libstd_thread_internals
8-
)]
7+
#[allow_internal_unstable(thread_local_internals)]
98
#[allow_internal_unsafe]
10-
macro_rules! __thread_local_inner {
9+
#[unstable(feature = "thread_local_internals", issue = "none")]
10+
#[rustc_macro_transparency = "semitransparent"]
11+
pub macro thread_local_inner {
1112
// used to generate the `LocalKey` value for const-initialized thread locals
1213
(@key $t:ty, const $init:expr) => {{
1314
#[cfg_attr(not(bootstrap), inline)]
@@ -21,8 +22,8 @@ macro_rules! __thread_local_inner {
2122
// same implementation as below for os thread locals.
2223
#[inline]
2324
const fn __init() -> $t { INIT_EXPR }
24-
static __KEY: $crate::thread::__LocalKeyInner<$t> =
25-
$crate::thread::__LocalKeyInner::new();
25+
static __KEY: $crate::thread::local_impl::Key<$t> =
26+
$crate::thread::local_impl::Key::new();
2627
#[allow(unused_unsafe)]
2728
unsafe {
2829
__KEY.get(move || {
@@ -41,7 +42,7 @@ macro_rules! __thread_local_inner {
4142
unsafe {
4243
$crate::thread::LocalKey::new(__getit)
4344
}
44-
}};
45+
}},
4546

4647
// used to generate the `LocalKey` value for `thread_local!`
4748
(@key $t:ty, $init:expr) => {
@@ -55,8 +56,8 @@ macro_rules! __thread_local_inner {
5556
unsafe fn __getit(
5657
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
5758
) -> $crate::option::Option<&'static $t> {
58-
static __KEY: $crate::thread::__LocalKeyInner<$t> =
59-
$crate::thread::__LocalKeyInner::new();
59+
static __KEY: $crate::thread::local_impl::Key<$t> =
60+
$crate::thread::local_impl::Key::new();
6061

6162
// FIXME: remove the #[allow(...)] marker when macros don't
6263
// raise warning for missing/extraneous unsafe blocks anymore.
@@ -80,118 +81,110 @@ macro_rules! __thread_local_inner {
8081
$crate::thread::LocalKey::new(__getit)
8182
}
8283
}
83-
};
84+
},
8485
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
8586
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
86-
$crate::__thread_local_inner!(@key $t, $($init)*);
87-
}
87+
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
88+
},
8889
}
8990

90-
#[doc(hidden)]
91-
pub mod os {
92-
use super::super::lazy::LazyKeyInner;
93-
use crate::cell::Cell;
94-
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
95-
use crate::{fmt, marker, panic, ptr};
96-
97-
/// Use a regular global static to store this key; the state provided will then be
98-
/// thread-local.
99-
pub struct Key<T> {
100-
// OS-TLS key that we'll use to key off.
101-
os: OsStaticKey,
102-
marker: marker::PhantomData<Cell<T>>,
103-
}
91+
/// Use a regular global static to store this key; the state provided will then be
92+
/// thread-local.
93+
pub struct Key<T> {
94+
// OS-TLS key that we'll use to key off.
95+
os: OsStaticKey,
96+
marker: marker::PhantomData<Cell<T>>,
97+
}
10498

105-
impl<T> fmt::Debug for Key<T> {
106-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107-
f.debug_struct("Key").finish_non_exhaustive()
108-
}
99+
impl<T> fmt::Debug for Key<T> {
100+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101+
f.debug_struct("Key").finish_non_exhaustive()
109102
}
103+
}
110104

111-
unsafe impl<T> Sync for Key<T> {}
105+
unsafe impl<T> Sync for Key<T> {}
112106

113-
struct Value<T: 'static> {
114-
inner: LazyKeyInner<T>,
115-
key: &'static Key<T>,
107+
struct Value<T: 'static> {
108+
inner: LazyKeyInner<T>,
109+
key: &'static Key<T>,
110+
}
111+
112+
impl<T: 'static> Key<T> {
113+
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
114+
pub const fn new() -> Key<T> {
115+
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
116116
}
117117

118-
impl<T: 'static> Key<T> {
119-
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
120-
pub const fn new() -> Key<T> {
121-
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
118+
/// It is a requirement for the caller to ensure that no mutable
119+
/// reference is active when this method is called.
120+
pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
121+
// SAFETY: See the documentation for this method.
122+
let ptr = unsafe { self.os.get() as *mut Value<T> };
123+
if ptr.addr() > 1 {
124+
// SAFETY: the check ensured the pointer is safe (its destructor
125+
// is not running) + it is coming from a trusted source (self).
126+
if let Some(ref value) = unsafe { (*ptr).inner.get() } {
127+
return Some(value);
128+
}
122129
}
130+
// SAFETY: At this point we are sure we have no value and so
131+
// initializing (or trying to) is safe.
132+
unsafe { self.try_initialize(init) }
133+
}
123134

124-
/// It is a requirement for the caller to ensure that no mutable
125-
/// reference is active when this method is called.
126-
pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
127-
// SAFETY: See the documentation for this method.
128-
let ptr = unsafe { self.os.get() as *mut Value<T> };
129-
if ptr.addr() > 1 {
130-
// SAFETY: the check ensured the pointer is safe (its destructor
131-
// is not running) + it is coming from a trusted source (self).
132-
if let Some(ref value) = unsafe { (*ptr).inner.get() } {
133-
return Some(value);
134-
}
135-
}
136-
// SAFETY: At this point we are sure we have no value and so
137-
// initializing (or trying to) is safe.
138-
unsafe { self.try_initialize(init) }
135+
// `try_initialize` is only called once per os thread local variable,
136+
// except in corner cases where thread_local dtors reference other
137+
// thread_local's, or it is being recursively initialized.
138+
unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
139+
// SAFETY: No mutable references are ever handed out meaning getting
140+
// the value is ok.
141+
let ptr = unsafe { self.os.get() as *mut Value<T> };
142+
if ptr.addr() == 1 {
143+
// destructor is running
144+
return None;
139145
}
140146

141-
// `try_initialize` is only called once per os thread local variable,
142-
// except in corner cases where thread_local dtors reference other
143-
// thread_local's, or it is being recursively initialized.
144-
unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
145-
// SAFETY: No mutable references are ever handed out meaning getting
146-
// the value is ok.
147-
let ptr = unsafe { self.os.get() as *mut Value<T> };
148-
if ptr.addr() == 1 {
149-
// destructor is running
150-
return None;
147+
let ptr = if ptr.is_null() {
148+
// If the lookup returned null, we haven't initialized our own
149+
// local copy, so do that now.
150+
let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));
151+
// SAFETY: At this point we are sure there is no value inside
152+
// ptr so setting it will not affect anyone else.
153+
unsafe {
154+
self.os.set(ptr as *mut u8);
151155
}
152-
153-
let ptr = if ptr.is_null() {
154-
// If the lookup returned null, we haven't initialized our own
155-
// local copy, so do that now.
156-
let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));
157-
// SAFETY: At this point we are sure there is no value inside
158-
// ptr so setting it will not affect anyone else.
159-
unsafe {
160-
self.os.set(ptr as *mut u8);
161-
}
162-
ptr
163-
} else {
164-
// recursive initialization
165-
ptr
166-
};
167-
168-
// SAFETY: ptr has been ensured as non-NUL just above an so can be
169-
// dereferenced safely.
170-
unsafe { Some((*ptr).inner.initialize(init)) }
171-
}
156+
ptr
157+
} else {
158+
// recursive initialization
159+
ptr
160+
};
161+
162+
// SAFETY: ptr has been ensured as non-NUL just above an so can be
163+
// dereferenced safely.
164+
unsafe { Some((*ptr).inner.initialize(init)) }
172165
}
166+
}
173167

174-
unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
175-
// SAFETY:
176-
//
177-
// The OS TLS ensures that this key contains a null value when this
178-
// destructor starts to run. We set it back to a sentinel value of 1 to
179-
// ensure that any future calls to `get` for this thread will return
180-
// `None`.
181-
//
182-
// Note that to prevent an infinite loop we reset it back to null right
183-
// before we return from the destructor ourselves.
184-
//
185-
// Wrap the call in a catch to ensure unwinding is caught in the event
186-
// a panic takes place in a destructor.
187-
if let Err(_) = panic::catch_unwind(|| unsafe {
188-
let ptr = Box::from_raw(ptr as *mut Value<T>);
189-
let key = ptr.key;
190-
key.os.set(ptr::invalid_mut(1));
191-
drop(ptr);
192-
key.os.set(ptr::null_mut());
193-
}) {
194-
rtabort!("thread local panicked on drop");
195-
}
168+
unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
169+
// SAFETY:
170+
//
171+
// The OS TLS ensures that this key contains a null value when this
172+
// destructor starts to run. We set it back to a sentinel value of 1 to
173+
// ensure that any future calls to `get` for this thread will return
174+
// `None`.
175+
//
176+
// Note that to prevent an infinite loop we reset it back to null right
177+
// before we return from the destructor ourselves.
178+
//
179+
// Wrap the call in a catch to ensure unwinding is caught in the event
180+
// a panic takes place in a destructor.
181+
if let Err(_) = panic::catch_unwind(|| unsafe {
182+
let ptr = Box::from_raw(ptr as *mut Value<T>);
183+
let key = ptr.key;
184+
key.os.set(ptr::invalid_mut(1));
185+
drop(ptr);
186+
key.os.set(ptr::null_mut());
187+
}) {
188+
rtabort!("thread local panicked on drop");
196189
}
197190
}
Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1+
use super::lazy::LazyKeyInner;
2+
use crate::fmt;
3+
14
#[doc(hidden)]
2-
#[macro_export]
3-
#[allow_internal_unstable(
4-
thread_local_internals,
5-
cfg_target_thread_local,
6-
thread_local,
7-
libstd_thread_internals
8-
)]
5+
#[allow_internal_unstable(thread_local_internals)]
96
#[allow_internal_unsafe]
10-
macro_rules! __thread_local_inner {
7+
#[unstable(feature = "thread_local_internals", issue = "none")]
8+
#[rustc_macro_transparency = "semitransparent"]
9+
pub macro thread_local_inner {
1110
// used to generate the `LocalKey` value for const-initialized thread locals
1211
(@key $t:ty, const $init:expr) => {{
1312
#[inline] // see comments below
@@ -30,7 +29,7 @@ macro_rules! __thread_local_inner {
3029
unsafe {
3130
$crate::thread::LocalKey::new(__getit)
3231
}
33-
}};
32+
}},
3433

3534
// used to generate the `LocalKey` value for `thread_local!`
3635
(@key $t:ty, $init:expr) => {
@@ -41,8 +40,8 @@ macro_rules! __thread_local_inner {
4140
unsafe fn __getit(
4241
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
4342
) -> $crate::option::Option<&'static $t> {
44-
static __KEY: $crate::thread::__LocalKeyInner<$t> =
45-
$crate::thread::__LocalKeyInner::new();
43+
static __KEY: $crate::thread::local_impl::Key<$t> =
44+
$crate::thread::local_impl::Key::new();
4645

4746
// FIXME: remove the #[allow(...)] marker when macros don't
4847
// raise warning for missing/extraneous unsafe blocks anymore.
@@ -66,50 +65,45 @@ macro_rules! __thread_local_inner {
6665
$crate::thread::LocalKey::new(__getit)
6766
}
6867
}
69-
};
68+
},
7069
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
7170
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
72-
$crate::__thread_local_inner!(@key $t, $($init)*);
73-
}
71+
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
72+
},
7473
}
7574

7675
/// On some targets like wasm there's no threads, so no need to generate
7776
/// thread locals and we can instead just use plain statics!
78-
#[doc(hidden)]
79-
pub mod statik {
80-
use super::super::lazy::LazyKeyInner;
81-
use crate::fmt;
8277

83-
pub struct Key<T> {
84-
inner: LazyKeyInner<T>,
85-
}
78+
pub struct Key<T> {
79+
inner: LazyKeyInner<T>,
80+
}
8681

87-
unsafe impl<T> Sync for Key<T> {}
82+
unsafe impl<T> Sync for Key<T> {}
8883

89-
impl<T> fmt::Debug for Key<T> {
90-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91-
f.debug_struct("Key").finish_non_exhaustive()
92-
}
84+
impl<T> fmt::Debug for Key<T> {
85+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86+
f.debug_struct("Key").finish_non_exhaustive()
9387
}
88+
}
9489

95-
impl<T> Key<T> {
96-
pub const fn new() -> Key<T> {
97-
Key { inner: LazyKeyInner::new() }
98-
}
90+
impl<T> Key<T> {
91+
pub const fn new() -> Key<T> {
92+
Key { inner: LazyKeyInner::new() }
93+
}
9994

100-
pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> {
101-
// SAFETY: The caller must ensure no reference is ever handed out to
102-
// the inner cell nor mutable reference to the Option<T> inside said
103-
// cell. This make it safe to hand a reference, though the lifetime
104-
// of 'static is itself unsafe, making the get method unsafe.
105-
let value = unsafe {
106-
match self.inner.get() {
107-
Some(ref value) => value,
108-
None => self.inner.initialize(init),
109-
}
110-
};
95+
pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> {
96+
// SAFETY: The caller must ensure no reference is ever handed out to
97+
// the inner cell nor mutable reference to the Option<T> inside said
98+
// cell. This make it safe to hand a reference, though the lifetime
99+
// of 'static is itself unsafe, making the get method unsafe.
100+
let value = unsafe {
101+
match self.inner.get() {
102+
Some(ref value) => value,
103+
None => self.inner.initialize(init),
104+
}
105+
};
111106

112-
Some(value)
113-
}
107+
Some(value)
114108
}
115109
}

‎library/std/src/thread/local.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,23 +153,23 @@ macro_rules! thread_local {
153153
() => {};
154154

155155
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
156-
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
156+
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
157157
$crate::thread_local!($($rest)*);
158158
);
159159

160160
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
161-
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
161+
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
162162
);
163163

164164
// process multiple declarations
165165
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
166-
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
166+
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
167167
$crate::thread_local!($($rest)*);
168168
);
169169

170170
// handle a single declaration
171171
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
172-
$crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
172+
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
173173
);
174174
}
175175

‎library/std/src/thread/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,12 @@ pub use self::local::{AccessError, LocalKey};
204204
// by the elf linker. "static" is for single-threaded platforms where a global
205205
// static is sufficient.
206206

207+
// Implementation details used by the thread_local!{} macro.
207208
#[doc(hidden)]
208-
#[unstable(feature = "libstd_thread_internals", issue = "none")]
209-
pub use crate::sys::common::thread_local::Key as __LocalKeyInner;
209+
#[unstable(feature = "thread_local_internals", issue = "none")]
210+
pub mod local_impl {
211+
pub use crate::sys::common::thread_local::{thread_local_inner, Key};
212+
}
210213

211214
////////////////////////////////////////////////////////////////////////////////
212215
// Builder

‎src/doc/unstable-book/src/library-features/libstd-thread-internals.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎tests/ui/macros/macro-local-data-key-priv.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ note: the constant `baz` is defined here
99
|
1010
LL | thread_local!(static baz: f64 = 0.0);
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12-
= note: this error originates in the macro `$crate::__thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
12+
= note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
1313

1414
error: aborting due to previous error
1515

‎tests/ui/threads-sendsync/issue-43733-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl<T> Key<T> {
2121
}
2222

2323
#[cfg(target_thread_local)]
24-
use std::thread::__LocalKeyInner as Key;
24+
use std::thread::local_impl::Key;
2525

2626
static __KEY: Key<()> = Key::new();
2727
//~^ ERROR `UnsafeCell<Option<()>>` cannot be shared between threads

‎tests/ui/threads-sendsync/issue-43733.mir.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
2-
--> $DIR/issue-43733.rs:21:5
2+
--> $DIR/issue-43733.rs:19:5
33
|
44
LL | __KEY.get(Default::default)
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

99
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
10-
--> $DIR/issue-43733.rs:26:42
10+
--> $DIR/issue-43733.rs:24:42
1111
|
1212
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function

‎tests/ui/threads-sendsync/issue-43733.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// ignore-wasm32
22
// revisions: mir thir
33
// [thir]compile-flags: -Z thir-unsafeck
4-
// normalize-stderr-test: "__LocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
5-
// normalize-stderr-test: "__LocalKeyInner::<T>::get" -> "$$LOCALKEYINNER::<T>::get"
64
#![feature(thread_local)]
75
#![feature(cfg_target_thread_local, thread_local_internals)]
86

@@ -12,15 +10,15 @@ type Foo = std::cell::RefCell<String>;
1210

1311
#[cfg(target_thread_local)]
1412
#[thread_local]
15-
static __KEY: std::thread::__LocalKeyInner<Foo> = std::thread::__LocalKeyInner::new();
13+
static __KEY: std::thread::local_impl::Key<Foo> = std::thread::local_impl::Key::new();
1614

1715
#[cfg(not(target_thread_local))]
18-
static __KEY: std::thread::__LocalKeyInner<Foo> = std::thread::__LocalKeyInner::new();
16+
static __KEY: std::thread::local_impl::Key<Foo> = std::thread::local_impl::Key::new();
1917

2018
fn __getit(_: Option<&mut Option<RefCell<String>>>) -> std::option::Option<&'static Foo> {
2119
__KEY.get(Default::default)
2220
//[mir]~^ ERROR call to unsafe function is unsafe
23-
//[thir]~^^ ERROR call to unsafe function `__
21+
//[thir]~^^ ERROR call to unsafe function `Key::<T>::get`
2422
}
2523

2624
static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);

‎tests/ui/threads-sendsync/issue-43733.thir.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error[E0133]: call to unsafe function `$LOCALKEYINNER::<T>::get` is unsafe and requires unsafe function or block
2-
--> $DIR/issue-43733.rs:21:5
1+
error[E0133]: call to unsafe function `Key::<T>::get` is unsafe and requires unsafe function or block
2+
--> $DIR/issue-43733.rs:19:5
33
|
44
LL | __KEY.get(Default::default)
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
66
|
77
= note: consult the function's documentation for information on how to avoid undefined behavior
88

99
error[E0133]: call to unsafe function `LocalKey::<T>::new` is unsafe and requires unsafe function or block
10-
--> $DIR/issue-43733.rs:26:42
10+
--> $DIR/issue-43733.rs:24:42
1111
|
1212
LL | static FOO: std::thread::LocalKey<Foo> = std::thread::LocalKey::new(__getit);
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function

0 commit comments

Comments
 (0)
This repository has been archived.