Skip to content

Commit 3150859

Browse files
committed
std: simplify key-based thread locals
1 parent e69f14b commit 3150859

File tree

2 files changed

+49
-76
lines changed

2 files changed

+49
-76
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ cfg_if::cfg_if! {
2424
}
2525
}
2626

27+
// FIXME(#110897): remove this
28+
#[allow(unused)] // Not used by key-based TLS.
2729
mod lazy {
2830
use crate::cell::UnsafeCell;
2931
use crate::hint;

library/std/src/sys/thread_local/os_local.rs

+47-76
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use super::lazy::LazyKeyInner;
21
use crate::cell::Cell;
2+
use crate::marker::PhantomData;
33
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
4-
use crate::{fmt, marker, panic, ptr};
4+
use crate::{panic, ptr};
55

66
#[doc(hidden)]
77
#[allow_internal_unstable(thread_local_internals)]
@@ -10,38 +10,9 @@ use crate::{fmt, marker, panic, ptr};
1010
#[rustc_macro_transparency = "semitransparent"]
1111
pub macro thread_local_inner {
1212
// used to generate the `LocalKey` value for const-initialized thread locals
13-
(@key $t:ty, const $init:expr) => {{
14-
#[inline]
15-
#[deny(unsafe_op_in_unsafe_fn)]
16-
unsafe fn __getit(
17-
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
18-
) -> $crate::option::Option<&'static $t> {
19-
const INIT_EXPR: $t = $init;
20-
21-
// On platforms without `#[thread_local]` we fall back to the
22-
// same implementation as below for os thread locals.
23-
#[inline]
24-
const fn __init() -> $t { INIT_EXPR }
25-
static __KEY: $crate::thread::local_impl::Key<$t> =
26-
$crate::thread::local_impl::Key::new();
27-
unsafe {
28-
__KEY.get(move || {
29-
if let $crate::option::Option::Some(init) = _init {
30-
if let $crate::option::Option::Some(value) = init.take() {
31-
return value;
32-
} else if $crate::cfg!(debug_assertions) {
33-
$crate::unreachable!("missing initial value");
34-
}
35-
}
36-
__init()
37-
})
38-
}
39-
}
40-
41-
unsafe {
42-
$crate::thread::LocalKey::new(__getit)
43-
}
44-
}},
13+
(@key $t:ty, const $init:expr) => {
14+
$crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR })
15+
},
4516

4617
// used to generate the `LocalKey` value for `thread_local!`
4718
(@key $t:ty, $init:expr) => {
@@ -85,78 +56,78 @@ pub macro thread_local_inner {
8556

8657
/// Use a regular global static to store this key; the state provided will then be
8758
/// thread-local.
59+
#[allow(missing_debug_implementations)]
8860
pub struct Key<T> {
8961
// OS-TLS key that we'll use to key off.
9062
os: OsStaticKey,
91-
marker: marker::PhantomData<Cell<T>>,
92-
}
93-
94-
impl<T> fmt::Debug for Key<T> {
95-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96-
f.debug_struct("Key").finish_non_exhaustive()
97-
}
63+
marker: PhantomData<Cell<T>>,
9864
}
9965

10066
unsafe impl<T> Sync for Key<T> {}
10167

10268
struct Value<T: 'static> {
103-
inner: LazyKeyInner<T>,
69+
value: T,
10470
key: &'static Key<T>,
10571
}
10672

10773
impl<T: 'static> Key<T> {
10874
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
10975
pub const fn new() -> Key<T> {
110-
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
76+
Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: PhantomData }
11177
}
11278

113-
/// It is a requirement for the caller to ensure that no mutable
114-
/// reference is active when this method is called.
79+
/// Get the value associated with this key, initializating it if necessary.
80+
///
81+
/// # Safety
82+
/// * the returned reference must not be used after recursive initialization
83+
/// or thread destruction occurs.
11584
pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
116-
// SAFETY: See the documentation for this method.
85+
// SAFETY: (FIXME: get should actually be safe)
11786
let ptr = unsafe { self.os.get() as *mut Value<T> };
11887
if ptr.addr() > 1 {
11988
// SAFETY: the check ensured the pointer is safe (its destructor
12089
// is not running) + it is coming from a trusted source (self).
121-
if let Some(ref value) = unsafe { (*ptr).inner.get() } {
122-
return Some(value);
123-
}
90+
unsafe { Some(&(*ptr).value) }
91+
} else {
92+
// SAFETY: At this point we are sure we have no value and so
93+
// initializing (or trying to) is safe.
94+
unsafe { self.try_initialize(ptr, init) }
12495
}
125-
// SAFETY: At this point we are sure we have no value and so
126-
// initializing (or trying to) is safe.
127-
unsafe { self.try_initialize(init) }
12896
}
12997

130-
// `try_initialize` is only called once per os thread local variable,
131-
// except in corner cases where thread_local dtors reference other
132-
// thread_local's, or it is being recursively initialized.
133-
unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> {
134-
// SAFETY: No mutable references are ever handed out meaning getting
135-
// the value is ok.
136-
let ptr = unsafe { self.os.get() as *mut Value<T> };
98+
/// Initialize an empty TLS key.
99+
///
100+
/// # Safety
101+
/// * the same requirements as for `get` apply
102+
/// * `ptr` must be the current value of the key, and must be either null or the sentinel value
103+
unsafe fn try_initialize(
104+
&'static self,
105+
ptr: *mut Value<T>,
106+
init: impl FnOnce() -> T,
107+
) -> Option<&'static T> {
137108
if ptr.addr() == 1 {
138109
// destructor is running
139110
return None;
140111
}
141112

142-
let ptr = if ptr.is_null() {
143-
// If the lookup returned null, we haven't initialized our own
144-
// local copy, so do that now.
145-
let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self }));
146-
// SAFETY: At this point we are sure there is no value inside
147-
// ptr so setting it will not affect anyone else.
148-
unsafe {
149-
self.os.set(ptr as *mut u8);
150-
}
151-
ptr
152-
} else {
153-
// recursive initialization
154-
ptr
155-
};
113+
let ptr = Box::into_raw(Box::new(Value { value: init(), key: self }));
114+
// SAFETY: (FIXME: get should actually be safe)
115+
let old = unsafe { self.os.get() as *mut Value<T> };
116+
// SAFETY: `ptr` is a correct pointer that can be destroyed by the key destructor.
117+
unsafe {
118+
self.os.set(ptr as *mut u8);
119+
}
120+
if !old.is_null() {
121+
// If the variable was recursively initialized, drop the old value.
122+
// SAFETY: We cannot be inside a `LocalKey::with` scope, as the
123+
// initializer has already returned and the next scope only starts
124+
// after we return the pointer. Therefore, there can be no references
125+
// to the old value.
126+
drop(unsafe { Box::from_raw(old) });
127+
}
156128

157-
// SAFETY: ptr has been ensured as non-NUL just above an so can be
158-
// dereferenced safely.
159-
unsafe { Some((*ptr).inner.initialize(init)) }
129+
// SAFETY: We just created this value above.
130+
unsafe { Some(&(*ptr).value) }
160131
}
161132
}
162133

0 commit comments

Comments
 (0)