Skip to content

Commit a4e87e9

Browse files
Support #[rustc_align_static] inside thread_local!
1 parent ae12bc2 commit a4e87e9

File tree

15 files changed

+872
-74
lines changed

15 files changed

+872
-74
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ cfg_select! {
4141
}
4242
_ => {
4343
mod os;
44-
pub use os::{Storage, thread_local_inner};
44+
pub use os::{Storage, thread_local_inner, value_align};
4545
pub(crate) use os::{LocalPointer, local_pointer};
4646
}
4747
}

library/std/src/sys/thread_local/native/eager.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ enum State {
1010
}
1111

1212
#[allow(missing_debug_implementations)]
13+
#[repr(C)]
1314
pub struct Storage<T> {
14-
state: Cell<State>,
15+
// This field must be first, for correctness of `#[rustc_align_static]`
1516
val: UnsafeCell<T>,
17+
state: Cell<State>,
1618
}
1719

1820
impl<T> Storage<T> {

library/std/src/sys/thread_local/native/lazy.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ enum State<D> {
2727
}
2828

2929
#[allow(missing_debug_implementations)]
30+
#[repr(C)]
3031
pub struct Storage<T, D> {
31-
state: Cell<State<D>>,
32+
// This field must be first, for correctness of `#[rustc_align_static]`
3233
value: UnsafeCell<MaybeUninit<T>>,
34+
state: Cell<State<D>>,
3335
}
3436

3537
impl<T, D> Storage<T, D>

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,23 @@ pub macro thread_local_inner {
5454
// test in `tests/thread.rs` if these types are renamed.
5555

5656
// Used to generate the `LocalKey` value for const-initialized thread locals.
57-
(@key $t:ty, const $init:expr) => {{
57+
(@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
5858
const __INIT: $t = $init;
5959

6060
unsafe {
6161
$crate::thread::LocalKey::new(const {
6262
if $crate::mem::needs_drop::<$t>() {
6363
|_| {
6464
#[thread_local]
65+
$(#[$align_attr])*
6566
static VAL: $crate::thread::local_impl::EagerStorage<$t>
6667
= $crate::thread::local_impl::EagerStorage::new(__INIT);
6768
VAL.get()
6869
}
6970
} else {
7071
|_| {
7172
#[thread_local]
73+
$(#[$align_attr])*
7274
static VAL: $t = __INIT;
7375
&VAL
7476
}
@@ -78,7 +80,7 @@ pub macro thread_local_inner {
7880
}},
7981

8082
// used to generate the `LocalKey` value for `thread_local!`
81-
(@key $t:ty, $init:expr) => {{
83+
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
8284
#[inline]
8385
fn __init() -> $t {
8486
$init
@@ -89,13 +91,15 @@ pub macro thread_local_inner {
8991
if $crate::mem::needs_drop::<$t>() {
9092
|init| {
9193
#[thread_local]
94+
$(#[$align_attr])*
9295
static VAL: $crate::thread::local_impl::LazyStorage<$t, ()>
9396
= $crate::thread::local_impl::LazyStorage::new();
9497
VAL.get_or_init(init, __init)
9598
}
9699
} else {
97100
|init| {
98101
#[thread_local]
102+
$(#[$align_attr])*
99103
static VAL: $crate::thread::local_impl::LazyStorage<$t, !>
100104
= $crate::thread::local_impl::LazyStorage::new();
101105
VAL.get_or_init(init, __init)
@@ -104,9 +108,9 @@ pub macro thread_local_inner {
104108
})
105109
}
106110
}},
107-
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
111+
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => {
108112
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
109-
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
113+
$crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*);
110114
},
111115
}
112116

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

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! thread locals and we can instead just use plain statics!
33
44
use crate::cell::{Cell, UnsafeCell};
5+
use crate::mem::MaybeUninit;
56
use crate::ptr;
67

78
#[doc(hidden)]
@@ -11,12 +12,13 @@ use crate::ptr;
1112
#[rustc_macro_transparency = "semitransparent"]
1213
pub macro thread_local_inner {
1314
// used to generate the `LocalKey` value for const-initialized thread locals
14-
(@key $t:ty, const $init:expr) => {{
15+
(@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
1516
const __INIT: $t = $init;
1617

1718
// NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
1819
unsafe {
1920
$crate::thread::LocalKey::new(|_| {
21+
$(#[$align_attr])*
2022
static VAL: $crate::thread::local_impl::EagerStorage<$t> =
2123
$crate::thread::local_impl::EagerStorage { value: __INIT };
2224
&VAL.value
@@ -25,42 +27,55 @@ pub macro thread_local_inner {
2527
}},
2628

2729
// used to generate the `LocalKey` value for `thread_local!`
28-
(@key $t:ty, $init:expr) => {{
30+
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
2931
#[inline]
3032
fn __init() -> $t { $init }
3133

3234
unsafe {
33-
use $crate::thread::LocalKey;
34-
use $crate::thread::local_impl::LazyStorage;
35-
36-
LocalKey::new(|init| {
37-
static VAL: LazyStorage<$t> = LazyStorage::new();
35+
$crate::thread::LocalKey::new(|init| {
36+
$(#[$align_attr])*
37+
static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
3838
VAL.get(init, __init)
3939
})
4040
}
4141
}},
42-
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
42+
43+
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $(#[$align_attr:meta])*, $($init:tt)*) => {
4344
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
44-
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
45+
$crate::thread::local_impl::thread_local_inner!(@key $t, $(#[$align_attr])*, $($init)*);
4546
},
4647
}
4748

4849
#[allow(missing_debug_implementations)]
50+
#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
4951
pub struct EagerStorage<T> {
5052
pub value: T,
5153
}
5254

5355
// SAFETY: the target doesn't have threads.
5456
unsafe impl<T> Sync for EagerStorage<T> {}
5557

58+
#[derive(Clone, Copy, PartialEq, Eq)]
59+
enum State {
60+
Initial,
61+
Alive,
62+
Destroying,
63+
}
64+
5665
#[allow(missing_debug_implementations)]
66+
#[repr(C)]
5767
pub struct LazyStorage<T> {
58-
value: UnsafeCell<Option<T>>,
68+
// This field must be first, for correctness of `#[rustc_align_static]`
69+
value: UnsafeCell<MaybeUninit<T>>,
70+
state: Cell<State>,
5971
}
6072

6173
impl<T> LazyStorage<T> {
6274
pub const fn new() -> LazyStorage<T> {
63-
LazyStorage { value: UnsafeCell::new(None) }
75+
LazyStorage {
76+
value: UnsafeCell::new(MaybeUninit::uninit()),
77+
state: Cell::new(State::Initial),
78+
}
6479
}
6580

6681
/// Gets a pointer to the TLS value, potentially initializing it with the
@@ -70,24 +85,39 @@ impl<T> LazyStorage<T> {
7085
/// has occurred.
7186
#[inline]
7287
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
73-
let value = unsafe { &*self.value.get() };
74-
match value {
75-
Some(v) => v,
76-
None => self.initialize(i, f),
88+
if self.state.get() == State::Alive {
89+
self.value.get() as *const T
90+
} else {
91+
self.initialize(i, f)
7792
}
7893
}
7994

8095
#[cold]
8196
fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
8297
let value = i.and_then(Option::take).unwrap_or_else(f);
83-
// Destroy the old value, after updating the TLS variable as the
84-
// destructor might reference it.
98+
99+
// Destroy the old value if it is initialized
85100
// FIXME(#110897): maybe panic on recursive initialization.
101+
if self.state.get() == State::Alive {
102+
self.state.set(State::Destroying);
103+
// Safety: we check for no initialization during drop below
104+
unsafe {
105+
ptr::drop_in_place(self.value.get() as *mut T);
106+
}
107+
self.state.set(State::Initial);
108+
}
109+
110+
// Guard against initialization during drop
111+
if self.state.get() == State::Destroying {
112+
panic!("Attempted to initialize thread-local while it is being dropped");
113+
}
114+
86115
unsafe {
87-
self.value.get().replace(Some(value));
116+
self.value.get().write(MaybeUninit::new(value));
88117
}
89-
// SAFETY: we just set this to `Some`.
90-
unsafe { (*self.value.get()).as_ref().unwrap_unchecked() }
118+
self.state.set(State::Alive);
119+
120+
self.value.get() as *const T
91121
}
92122
}
93123

0 commit comments

Comments
 (0)