Skip to content

Commit ad8a3b4

Browse files
os impl: use const generic for alignment
1 parent 3decba5 commit ad8a3b4

File tree

2 files changed

+34
-40
lines changed

2 files changed

+34
-40
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/os.rs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,34 @@ pub macro thread_local_inner {
3030
// in `tests/thread.rs` if these types are renamed.
3131
unsafe {
3232
$crate::thread::LocalKey::new(|init| {
33-
static VAL: $crate::thread::local_impl::Storage<$t>
33+
const ALIGN: usize = $crate::thread::local_impl::thread_local_inner!(@align $t, $(#[$($align_attr)*])*);
34+
static VAL: $crate::thread::local_impl::Storage<$t, ALIGN>
3435
= $crate::thread::local_impl::Storage::new();
35-
VAL.get($crate::thread::local_impl::thread_local_inner!(@align $(#[$($align_attr)*])*), init, __init)
36+
VAL.get(init, __init)
3637
})
3738
}
3839
}},
3940

4041
// Handle `rustc_align_static` attributes,
4142
// by translating them into an argumemt to pass to `Storage::get`:
4243

43-
// fast path for when there are none
44-
(@align) => (1),
44+
// fast path
45+
(@align $t:ty,) => { $crate::thread::local_impl::value_align::<$t>() },
4546

4647
// `rustc_align_static` attributes are present,
4748
// translate them into a `const` block that computes the alignment
48-
(@align $(#[$($attr:tt)*])+) => {
49-
const {
50-
// Ensure that attributes have valid syntax
51-
// and that the proper feature gate is enabled
52-
$(#[$($attr)*])+
53-
static DUMMY: () = ();
54-
55-
let mut final_align = 1_usize;
56-
$($crate::thread::local_impl::thread_local_inner!(@align_single final_align, $($attr)*);)+
57-
final_align
58-
}
59-
},
49+
(@align $t:ty, $(#[$($attr:tt)*])+) => {{
50+
// Ensure that attributes have valid syntax
51+
// and that the proper feature gate is enabled
52+
$(#[$($attr)*])*
53+
#[allow(unused)]
54+
static DUMMY: () = ();
55+
56+
#[allow(unused_mut)]
57+
let mut final_align = $crate::thread::local_impl::value_align::<$t>();
58+
$($crate::thread::local_impl::thread_local_inner!(@align_single final_align, $($attr)*);)+
59+
final_align
60+
}},
6061

6162
// process a single `rustc_align_static` attribute
6263
(@align_single $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => {
@@ -107,26 +108,30 @@ pub macro thread_local_inner {
107108

108109
/// Use a regular global static to store this key; the state provided will then be
109110
/// thread-local.
111+
/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`.
110112
#[allow(missing_debug_implementations)]
111-
pub struct Storage<T> {
113+
pub struct Storage<T, const ALIGN: usize> {
112114
key: LazyKey,
113115
marker: PhantomData<Cell<T>>,
114116
}
115117

116-
unsafe impl<T> Sync for Storage<T> {}
118+
unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {}
117119

118120
#[repr(C)]
119121
struct Value<T: 'static> {
120122
// This field must be first, for correctness of `#[rustc_align_static]`
121123
value: T,
122-
align: usize,
123124
// INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
124125
key: Key,
125126
}
126127

127-
impl<T: 'static> Storage<T> {
128-
pub const fn new() -> Storage<T> {
129-
Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
128+
pub const fn value_align<T: 'static>() -> usize {
129+
crate::mem::align_of::<Value<T>>()
130+
}
131+
132+
impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> {
133+
pub const fn new() -> Storage<T, ALIGN> {
134+
Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData }
130135
}
131136

132137
/// Gets a pointer to the TLS value, potentially initializing it with the
@@ -135,12 +140,7 @@ impl<T: 'static> Storage<T> {
135140
///
136141
/// The resulting pointer may not be used after reentrant inialialization
137142
/// or thread destruction has occurred.
138-
pub fn get(
139-
&'static self,
140-
align: usize,
141-
i: Option<&mut Option<T>>,
142-
f: impl FnOnce() -> T,
143-
) -> *const T {
143+
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
144144
let key = self.key.force();
145145
let ptr = unsafe { get(key) as *mut Value<T> };
146146
if ptr.addr() > 1 {
@@ -149,7 +149,7 @@ impl<T: 'static> Storage<T> {
149149
unsafe { &(*ptr).value }
150150
} else {
151151
// SAFETY: trivially correct.
152-
unsafe { Self::try_initialize(key, align, ptr, i, f) }
152+
unsafe { Self::try_initialize(key, ptr, i, f) }
153153
}
154154
}
155155

@@ -158,7 +158,6 @@ impl<T: 'static> Storage<T> {
158158
/// * `ptr` must be the current value associated with `key`.
159159
unsafe fn try_initialize(
160160
key: Key,
161-
align: usize,
162161
ptr: *mut Value<T>,
163162
i: Option<&mut Option<T>>,
164163
f: impl FnOnce() -> T,
@@ -169,17 +168,13 @@ impl<T: 'static> Storage<T> {
169168
}
170169

171170
// Manually allocate with the requested alignment
172-
let layout = Layout::new::<Value<T>>().align_to(align).unwrap();
171+
let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
173172
let ptr: *mut Value<T> = (unsafe { crate::alloc::alloc(layout) }).cast();
174173
if ptr.is_null() {
175174
crate::alloc::handle_alloc_error(layout);
176175
}
177176
unsafe {
178-
ptr.write(Value {
179-
value: i.and_then(Option::take).unwrap_or_else(f),
180-
align: layout.align(),
181-
key,
182-
});
177+
ptr.write(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
183178
}
184179

185180
// SAFETY:
@@ -209,7 +204,7 @@ impl<T: 'static> Storage<T> {
209204
}
210205
}
211206

212-
unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
207+
unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) {
213208
// SAFETY:
214209
//
215210
// The OS TLS ensures that this key contains a null value when this
@@ -223,14 +218,13 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
223218
let value_ptr: *mut Value<T> = ptr.cast();
224219
unsafe {
225220
let key = (*value_ptr).key;
226-
let align = (*value_ptr).align;
227221

228222
// SAFETY: `key` is the TLS key `ptr` was stored under.
229223
set(key, ptr::without_provenance_mut(1));
230224

231225
// drop and deallocate the value
232226
let layout =
233-
Layout::from_size_align_unchecked(crate::mem::size_of::<Value<T>>(), align);
227+
Layout::from_size_align_unchecked(crate::mem::size_of::<Value<T>>(), ALIGN);
234228
value_ptr.drop_in_place();
235229
crate::alloc::dealloc(ptr, layout);
236230

0 commit comments

Comments
 (0)