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 078095a

Browse files
committedMay 24, 2024
std: make TLS accessors closures that return pointers
1 parent 5af5f81 commit 078095a

File tree

6 files changed

+107
-180
lines changed

6 files changed

+107
-180
lines changed
 

‎std/src/sys/thread_local/fast_local/eager.rs

+13-21
Original file line numberDiff line numberDiff line change
@@ -21,43 +21,35 @@ impl<T> Storage<T> {
2121
Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) }
2222
}
2323

24-
/// Get a reference to the TLS value. If the TLS variable has been destroyed,
25-
/// `None` is returned.
24+
/// Get a pointer to the TLS value. If the TLS variable has been destroyed,
25+
/// a null pointer is returned.
2626
///
27-
/// # Safety
28-
/// * The `self` reference must remain valid until the TLS destructor has been
29-
/// run.
30-
/// * The returned reference may only be used until thread destruction occurs
31-
/// and may not be used after reentrant initialization has occurred.
27+
/// The resulting pointer may not be used after thread destruction has
28+
/// occurred.
3229
///
33-
// FIXME(#110897): return NonNull instead of lying about the lifetime.
30+
/// # Safety
31+
/// The `self` reference must remain valid until the TLS destructor is run.
3432
#[inline]
35-
pub unsafe fn get(&self) -> Option<&'static T> {
33+
pub unsafe fn get(&self) -> *const T {
3634
match self.state.get() {
37-
// SAFETY: as the state is not `Destroyed`, the value cannot have
38-
// been destroyed yet. The reference fulfills the terms outlined
39-
// above.
40-
State::Alive => unsafe { Some(&*self.val.get()) },
41-
State::Destroyed => None,
35+
State::Alive => self.val.get(),
36+
State::Destroyed => ptr::null(),
4237
State::Initial => unsafe { self.initialize() },
4338
}
4439
}
4540

4641
#[cold]
47-
unsafe fn initialize(&self) -> Option<&'static T> {
42+
unsafe fn initialize(&self) -> *const T {
4843
// Register the destructor
4944

5045
// SAFETY:
51-
// * the destructor will be called at thread destruction.
52-
// * the caller guarantees that `self` will be valid until that time.
46+
// The caller guarantees that `self` will be valid until thread destruction.
5347
unsafe {
5448
register_dtor(ptr::from_ref(self).cast_mut().cast(), destroy::<T>);
5549
}
50+
5651
self.state.set(State::Alive);
57-
// SAFETY: as the state is not `Destroyed`, the value cannot have
58-
// been destroyed yet. The reference fulfills the terms outlined
59-
// above.
60-
unsafe { Some(&*self.val.get()) }
52+
self.val.get()
6153
}
6254
}
6355

‎std/src/sys/thread_local/fast_local/lazy.rs

+13-33
Original file line numberDiff line numberDiff line change
@@ -39,49 +39,31 @@ where
3939
Storage { state: UnsafeCell::new(State::Initial) }
4040
}
4141

42-
/// Get a reference to the TLS value, potentially initializing it with the
43-
/// provided parameters. If the TLS variable has been destroyed, `None` is
44-
/// returned.
42+
/// Get a pointer to the TLS value, potentially initializing it with the
43+
/// provided parameters. If the TLS variable has been destroyed, a null
44+
/// pointer is returned.
4545
///
46-
/// # Safety
47-
/// * The `self` reference must remain valid until the TLS destructor is run,
48-
/// at which point the returned reference is invalidated.
49-
/// * The returned reference may only be used until thread destruction occurs
50-
/// and may not be used after reentrant initialization has occurred.
46+
/// The resulting pointer may not be used after reentrant inialialization
47+
/// or thread destruction has occurred.
5148
///
52-
// FIXME(#110897): return NonNull instead of lying about the lifetime.
49+
/// # Safety
50+
/// The `self` reference must remain valid until the TLS destructor is run.
5351
#[inline]
54-
pub unsafe fn get_or_init(
55-
&self,
56-
i: Option<&mut Option<T>>,
57-
f: impl FnOnce() -> T,
58-
) -> Option<&'static T> {
59-
// SAFETY:
60-
// No mutable reference to the inner value exists outside the calls to
61-
// `replace`. The lifetime of the returned reference fulfills the terms
62-
// outlined above.
52+
pub unsafe fn get_or_init(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
6353
let state = unsafe { &*self.state.get() };
6454
match state {
65-
State::Alive(v) => Some(v),
66-
State::Destroyed(_) => None,
55+
State::Alive(v) => v,
56+
State::Destroyed(_) => ptr::null(),
6757
State::Initial => unsafe { self.initialize(i, f) },
6858
}
6959
}
7060

7161
#[cold]
72-
unsafe fn initialize(
73-
&self,
74-
i: Option<&mut Option<T>>,
75-
f: impl FnOnce() -> T,
76-
) -> Option<&'static T> {
62+
unsafe fn initialize(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
7763
// Perform initialization
7864

7965
let v = i.and_then(Option::take).unwrap_or_else(f);
8066

81-
// SAFETY:
82-
// If references to the inner value exist, they were created in `f`
83-
// and are invalidated here. The caller promises to never use them
84-
// after this.
8567
let old = unsafe { self.state.get().replace(State::Alive(v)) };
8668
match old {
8769
// If the variable is not being recursively initialized, register
@@ -92,12 +74,10 @@ where
9274
val => drop(val),
9375
}
9476

95-
// SAFETY:
96-
// Initialization was completed and the state was set to `Alive`, so the
97-
// reference fulfills the terms outlined above.
77+
// SAFETY: the state was just set to `Alive`
9878
unsafe {
9979
let State::Alive(v) = &*self.state.get() else { unreachable_unchecked() };
100-
Some(v)
80+
v
10181
}
10282
}
10383
}

‎std/src/sys/thread_local/fast_local/mod.rs

+34-45
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,26 @@ pub macro thread_local_inner {
5252
(@key $t:ty, const $init:expr) => {{
5353
const __INIT: $t = $init;
5454

55-
#[inline]
56-
#[deny(unsafe_op_in_unsafe_fn)]
57-
unsafe fn __getit(
58-
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
59-
) -> $crate::option::Option<&'static $t> {
60-
use $crate::thread::local_impl::EagerStorage;
55+
unsafe {
6156
use $crate::mem::needs_drop;
62-
use $crate::ptr::addr_of;
57+
use $crate::thread::LocalKey;
58+
use $crate::thread::local_impl::EagerStorage;
6359

64-
if needs_drop::<$t>() {
65-
#[thread_local]
66-
static VAL: EagerStorage<$t> = EagerStorage::new(__INIT);
67-
unsafe {
68-
VAL.get()
60+
LocalKey::new(const {
61+
if needs_drop::<$t>() {
62+
|_| {
63+
#[thread_local]
64+
static VAL: EagerStorage<$t> = EagerStorage::new(__INIT);
65+
VAL.get()
66+
}
67+
} else {
68+
|_| {
69+
#[thread_local]
70+
static VAL: $t = __INIT;
71+
&VAL
72+
}
6973
}
70-
} else {
71-
#[thread_local]
72-
static VAL: $t = __INIT;
73-
unsafe {
74-
$crate::option::Option::Some(&*addr_of!(VAL))
75-
}
76-
}
77-
}
78-
79-
unsafe {
80-
$crate::thread::LocalKey::new(__getit)
74+
})
8175
}
8276
}},
8377

@@ -88,31 +82,26 @@ pub macro thread_local_inner {
8882
$init
8983
}
9084

91-
#[inline]
92-
#[deny(unsafe_op_in_unsafe_fn)]
93-
unsafe fn __getit(
94-
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
95-
) -> $crate::option::Option<&'static $t> {
96-
use $crate::thread::local_impl::LazyStorage;
85+
unsafe {
9786
use $crate::mem::needs_drop;
87+
use $crate::thread::LocalKey;
88+
use $crate::thread::local_impl::LazyStorage;
9889

99-
if needs_drop::<$t>() {
100-
#[thread_local]
101-
static VAL: LazyStorage<$t, ()> = LazyStorage::new();
102-
unsafe {
103-
VAL.get_or_init(init, __init)
90+
LocalKey::new(const {
91+
if needs_drop::<$t>() {
92+
|init| {
93+
#[thread_local]
94+
static VAL: LazyStorage<$t, ()> = LazyStorage::new();
95+
VAL.get_or_init(init, __init)
96+
}
97+
} else {
98+
|init| {
99+
#[thread_local]
100+
static VAL: LazyStorage<$t, !> = LazyStorage::new();
101+
VAL.get_or_init(init, __init)
102+
}
104103
}
105-
} else {
106-
#[thread_local]
107-
static VAL: LazyStorage<$t, !> = LazyStorage::new();
108-
unsafe {
109-
VAL.get_or_init(init, __init)
110-
}
111-
}
112-
}
113-
114-
unsafe {
115-
$crate::thread::LocalKey::new(__getit)
104+
})
116105
}
117106
}},
118107
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {

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

+25-38
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,22 @@ pub macro thread_local_inner {
1616
},
1717

1818
// used to generate the `LocalKey` value for `thread_local!`
19-
(@key $t:ty, $init:expr) => {
20-
{
21-
#[inline]
22-
fn __init() -> $t { $init }
19+
(@key $t:ty, $init:expr) => {{
20+
#[inline]
21+
fn __init() -> $t { $init }
2322

24-
// `#[inline] does not work on windows-gnu due to linking errors around dllimports.
25-
// See https://github.com/rust-lang/rust/issues/109797.
26-
#[cfg_attr(not(windows), inline)]
27-
unsafe fn __getit(
28-
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
29-
) -> $crate::option::Option<&'static $t> {
30-
use $crate::thread::local_impl::Key;
31-
32-
static __KEY: Key<$t> = Key::new();
33-
unsafe {
34-
__KEY.get(init, __init)
35-
}
36-
}
23+
unsafe {
24+
use $crate::thread::LocalKey;
25+
use $crate::thread::local_impl::Key;
3726

38-
unsafe {
39-
$crate::thread::LocalKey::new(__getit)
40-
}
27+
// Inlining does not work on windows-gnu due to linking errors around
28+
// dllimports. See https://github.com/rust-lang/rust/issues/109797.
29+
LocalKey::new(#[cfg_attr(windows, inline(never))] |init| {
30+
static VAL: Key<$t> = Key::new();
31+
VAL.get(init, __init)
32+
})
4133
}
42-
},
34+
}},
4335
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
4436
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
4537
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
@@ -67,38 +59,33 @@ impl<T: 'static> Key<T> {
6759
Key { os: OsKey::new(Some(destroy_value::<T>)), marker: PhantomData }
6860
}
6961

70-
/// Get the value associated with this key, initializating it if necessary.
62+
/// Get a pointer to the TLS value, potentially initializing it with the
63+
/// provided parameters. If the TLS variable has been destroyed, a null
64+
/// pointer is returned.
7165
///
72-
/// # Safety
73-
/// * the returned reference must not be used after recursive initialization
74-
/// or thread destruction occurs.
75-
pub unsafe fn get(
76-
&'static self,
77-
i: Option<&mut Option<T>>,
78-
f: impl FnOnce() -> T,
79-
) -> Option<&'static T> {
66+
/// The resulting pointer may not be used after reentrant inialialization
67+
/// or thread destruction has occurred.
68+
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
8069
// SAFETY: (FIXME: get should actually be safe)
8170
let ptr = unsafe { self.os.get() as *mut Value<T> };
8271
if ptr.addr() > 1 {
8372
// SAFETY: the check ensured the pointer is safe (its destructor
8473
// is not running) + it is coming from a trusted source (self).
85-
unsafe { Some(&(*ptr).value) }
74+
unsafe { &(*ptr).value }
8675
} else {
87-
// SAFETY: At this point we are sure we have no value and so
88-
// initializing (or trying to) is safe.
89-
unsafe { self.try_initialize(ptr, i, f) }
76+
self.try_initialize(ptr, i, f)
9077
}
9178
}
9279

93-
unsafe fn try_initialize(
80+
fn try_initialize(
9481
&'static self,
9582
ptr: *mut Value<T>,
9683
i: Option<&mut Option<T>>,
9784
f: impl FnOnce() -> T,
98-
) -> Option<&'static T> {
85+
) -> *const T {
9986
if ptr.addr() == 1 {
10087
// destructor is running
101-
return None;
88+
return ptr::null();
10289
}
10390

10491
let value = i.and_then(Option::take).unwrap_or_else(f);
@@ -119,7 +106,7 @@ impl<T: 'static> Key<T> {
119106
}
120107

121108
// SAFETY: We just created this value above.
122-
unsafe { Some(&(*ptr).value) }
109+
unsafe { &(*ptr).value }
123110
}
124111
}
125112

There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.