std/sys/thread_local/
os.rs1use super::key::{Key, LazyKey, get, set};
2use super::{abort_on_dtor_unwind, guard};
3use crate::alloc::{self, GlobalAlloc, Layout, System};
4use crate::cell::Cell;
5use crate::marker::PhantomData;
6use crate::mem::ManuallyDrop;
7use crate::ops::Deref;
8use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
9use crate::ptr::{self, NonNull};
10
11#[doc(hidden)]
12#[allow_internal_unstable(thread_local_internals)]
13#[allow_internal_unsafe]
14#[unstable(feature = "thread_local_internals", issue = "none")]
15#[rustc_macro_transparency = "semiopaque"]
16pub macro thread_local_inner {
17 (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{
23 #[inline]
24 fn __rust_std_internal_init_fn() -> $t { $init }
25
26 unsafe {
30 $crate::thread::LocalKey::new(|__rust_std_internal_init| {
31 static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::Storage<$t, {
32 $({
33 $(#[$($align_attr)*])+
36 #[allow(unused)]
37 static DUMMY: () = ();
38 })?
39
40 #[allow(unused_mut)]
41 let mut final_align = $crate::thread::local_impl::value_align::<$t>();
42 $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)?
43 final_align
44 }>
45 = $crate::thread::local_impl::Storage::new();
46 __RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn)
47 })
48 }
49 }},
50
51 (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => {
53 let new_align: $crate::primitive::usize = $($align)*;
54 if new_align > $final_align {
55 $final_align = new_align;
56 }
57
58 $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
59 },
60
61 (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
66 #[cfg(true)]
67 {
68 $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
69 }
70
71 $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
72 },
73
74 (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
75 #[cfg(false)]
76 {
77 $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
78 }
79
80 $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
81 },
82
83 (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
84 #[cfg($cfg_pred)]
85 {
86 $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
87 }
88
89 $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
90 },
91}
92
93#[allow(missing_debug_implementations)]
97pub struct Storage<T, const ALIGN: usize> {
98 key: LazyKey,
99 marker: PhantomData<Cell<T>>,
100}
101
102unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {}
103
104#[repr(C)]
105struct Value<T: 'static> {
106 value: T,
108 key: Key,
110}
111
112pub const fn value_align<T: 'static>() -> usize {
113 crate::mem::align_of::<Value<T>>()
114}
115
116struct AlignedSystemBox<T: 'static, const ALIGN: usize> {
118 ptr: NonNull<Value<T>>,
119}
120
121impl<T: 'static, const ALIGN: usize> AlignedSystemBox<T, ALIGN> {
122 #[inline]
123 fn new(v: Value<T>) -> Self {
124 let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
125
126 let ptr: *mut Value<T> = (unsafe { System.alloc(layout) }).cast();
129 let Some(ptr) = NonNull::new(ptr) else {
130 alloc::handle_alloc_error(layout);
131 };
132 unsafe { ptr.write(v) };
133 Self { ptr }
134 }
135
136 #[inline]
137 fn into_raw(b: Self) -> *mut Value<T> {
138 let md = ManuallyDrop::new(b);
139 md.ptr.as_ptr()
140 }
141
142 #[inline]
143 unsafe fn from_raw(ptr: *mut Value<T>) -> Self {
144 Self { ptr: unsafe { NonNull::new_unchecked(ptr) } }
145 }
146}
147
148impl<T: 'static, const ALIGN: usize> Deref for AlignedSystemBox<T, ALIGN> {
149 type Target = Value<T>;
150
151 #[inline]
152 fn deref(&self) -> &Self::Target {
153 unsafe { &*(self.ptr.as_ptr()) }
154 }
155}
156
157impl<T: 'static, const ALIGN: usize> Drop for AlignedSystemBox<T, ALIGN> {
158 #[inline]
159 fn drop(&mut self) {
160 let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
161
162 unsafe {
163 let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place()));
164 System.dealloc(self.ptr.as_ptr().cast(), layout);
165 if let Err(payload) = unwind_result {
166 resume_unwind(payload);
167 }
168 }
169 }
170}
171
172impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> {
173 pub const fn new() -> Storage<T, ALIGN> {
174 Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData }
175 }
176
177 pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
184 let key = self.key.force();
185 let ptr = unsafe { get(key) as *mut Value<T> };
186 if ptr.addr() > 1 {
187 unsafe { &(*ptr).value }
190 } else {
191 unsafe { Self::try_initialize(key, ptr, i, f) }
193 }
194 }
195
196 unsafe fn try_initialize(
200 key: Key,
201 ptr: *mut Value<T>,
202 i: Option<&mut Option<T>>,
203 f: impl FnOnce() -> T,
204 ) -> *const T {
205 if ptr.addr() == 1 {
206 return ptr::null();
208 }
209
210 let value = AlignedSystemBox::<T, ALIGN>::new(Value {
211 value: i.and_then(Option::take).unwrap_or_else(f),
212 key,
213 });
214 let ptr = AlignedSystemBox::into_raw(value);
215
216 let old = unsafe {
221 let old = get(key) as *mut Value<T>;
222 set(key, ptr as *mut u8);
223 old
224 };
225
226 if !old.is_null() {
227 drop(unsafe { AlignedSystemBox::<T, ALIGN>::from_raw(old) });
233 }
234
235 unsafe { &(*ptr).value }
237 }
238}
239
240unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) {
241 abort_on_dtor_unwind(|| {
251 let ptr = unsafe { AlignedSystemBox::<T, ALIGN>::from_raw(ptr as *mut Value<T>) };
252 let key = ptr.key;
253 unsafe { set(key, ptr::without_provenance_mut(1)) };
255 drop(ptr);
256 unsafe { set(key, ptr::null_mut()) };
258 guard::enable();
261 });
262}
263
264#[rustc_macro_transparency = "semiopaque"]
265pub(crate) macro local_pointer {
266 () => {},
267 ($vis:vis static $name:ident; $($rest:tt)*) => {
268 $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
269 $crate::sys::thread_local::local_pointer! { $($rest)* }
270 },
271}
272
273pub(crate) struct LocalPointer {
274 key: LazyKey,
275}
276
277impl LocalPointer {
278 pub const fn __new() -> LocalPointer {
279 LocalPointer { key: LazyKey::new(None) }
280 }
281
282 pub fn get(&'static self) -> *mut () {
283 unsafe { get(self.key.force()) as *mut () }
284 }
285
286 pub fn set(&'static self, p: *mut ()) {
287 unsafe { set(self.key.force(), p as *mut u8) }
288 }
289}