std\sys\thread_local/os.rs
1use super::key::{Key, LazyKey, get, set};
2use super::{abort_on_dtor_unwind, guard};
3use crate::cell::Cell;
4use crate::marker::PhantomData;
5use crate::ptr;
6
7#[doc(hidden)]
8#[allow_internal_unstable(thread_local_internals)]
9#[allow_internal_unsafe]
10#[unstable(feature = "thread_local_internals", issue = "none")]
11#[rustc_macro_transparency = "semitransparent"]
12pub macro thread_local_inner {
13 // used to generate the `LocalKey` value for const-initialized thread locals
14 (@key $t:ty, const $init:expr) => {
15 $crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR })
16 },
17
18 // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user
19 // provided type or type alias with a matching name. Please update the shadowing test in
20 // `tests/thread.rs` if these types are renamed.
21
22 // used to generate the `LocalKey` value for `thread_local!`.
23 (@key $t:ty, $init:expr) => {{
24 #[inline]
25 fn __init() -> $t { $init }
26
27 // NOTE: this cannot import `LocalKey` or `Storage` with a `use` because that can shadow
28 // user provided type or type alias with a matching name. Please update the shadowing test
29 // in `tests/thread.rs` if these types are renamed.
30 unsafe {
31 // Inlining does not work on windows-gnu due to linking errors around
32 // dllimports. See https://github.com/rust-lang/rust/issues/109797.
33 $crate::thread::LocalKey::new(#[cfg_attr(windows, inline(never))] |init| {
34 static VAL: $crate::thread::local_impl::Storage<$t>
35 = $crate::thread::local_impl::Storage::new();
36 VAL.get(init, __init)
37 })
38 }
39 }},
40 ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
41 $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
42 $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
43 },
44}
45
46/// Use a regular global static to store this key; the state provided will then be
47/// thread-local.
48#[allow(missing_debug_implementations)]
49pub struct Storage<T> {
50 key: LazyKey,
51 marker: PhantomData<Cell<T>>,
52}
53
54unsafe impl<T> Sync for Storage<T> {}
55
56struct Value<T: 'static> {
57 value: T,
58 // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
59 key: Key,
60}
61
62impl<T: 'static> Storage<T> {
63 pub const fn new() -> Storage<T> {
64 Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
65 }
66
67 /// Gets a pointer to the TLS value, potentially initializing it with the
68 /// provided parameters. If the TLS variable has been destroyed, a null
69 /// pointer is returned.
70 ///
71 /// The resulting pointer may not be used after reentrant inialialization
72 /// or thread destruction has occurred.
73 pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
74 let key = self.key.force();
75 let ptr = unsafe { get(key) as *mut Value<T> };
76 if ptr.addr() > 1 {
77 // SAFETY: the check ensured the pointer is safe (its destructor
78 // is not running) + it is coming from a trusted source (self).
79 unsafe { &(*ptr).value }
80 } else {
81 // SAFETY: trivially correct.
82 unsafe { Self::try_initialize(key, ptr, i, f) }
83 }
84 }
85
86 /// # Safety
87 /// * `key` must be the result of calling `self.key.force()`
88 /// * `ptr` must be the current value associated with `key`.
89 unsafe fn try_initialize(
90 key: Key,
91 ptr: *mut Value<T>,
92 i: Option<&mut Option<T>>,
93 f: impl FnOnce() -> T,
94 ) -> *const T {
95 if ptr.addr() == 1 {
96 // destructor is running
97 return ptr::null();
98 }
99
100 let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
101 let ptr = Box::into_raw(value);
102
103 // SAFETY:
104 // * key came from a `LazyKey` and is thus correct.
105 // * `ptr` is a correct pointer that can be destroyed by the key destructor.
106 // * the value is stored under the key that it contains.
107 let old = unsafe {
108 let old = get(key) as *mut Value<T>;
109 set(key, ptr as *mut u8);
110 old
111 };
112
113 if !old.is_null() {
114 // If the variable was recursively initialized, drop the old value.
115 // SAFETY: We cannot be inside a `LocalKey::with` scope, as the
116 // initializer has already returned and the next scope only starts
117 // after we return the pointer. Therefore, there can be no references
118 // to the old value.
119 drop(unsafe { Box::from_raw(old) });
120 }
121
122 // SAFETY: We just created this value above.
123 unsafe { &(*ptr).value }
124 }
125}
126
127unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
128 // SAFETY:
129 //
130 // The OS TLS ensures that this key contains a null value when this
131 // destructor starts to run. We set it back to a sentinel value of 1 to
132 // ensure that any future calls to `get` for this thread will return
133 // `None`.
134 //
135 // Note that to prevent an infinite loop we reset it back to null right
136 // before we return from the destructor ourselves.
137 abort_on_dtor_unwind(|| {
138 let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) };
139 let key = ptr.key;
140 // SAFETY: `key` is the TLS key `ptr` was stored under.
141 unsafe { set(key, ptr::without_provenance_mut(1)) };
142 drop(ptr);
143 // SAFETY: `key` is the TLS key `ptr` was stored under.
144 unsafe { set(key, ptr::null_mut()) };
145 // Make sure that the runtime cleanup will be performed
146 // after the next round of TLS destruction.
147 guard::enable();
148 });
149}
150
151#[rustc_macro_transparency = "semitransparent"]
152pub(crate) macro local_pointer {
153 () => {},
154 ($vis:vis static $name:ident; $($rest:tt)*) => {
155 $vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
156 $crate::sys::thread_local::local_pointer! { $($rest)* }
157 },
158}
159
160pub(crate) struct LocalPointer {
161 key: LazyKey,
162}
163
164impl LocalPointer {
165 pub const fn __new() -> LocalPointer {
166 LocalPointer { key: LazyKey::new(None) }
167 }
168
169 pub fn get(&'static self) -> *mut () {
170 unsafe { get(self.key.force()) as *mut () }
171 }
172
173 pub fn set(&'static self, p: *mut ()) {
174 unsafe { set(self.key.force(), p as *mut u8) }
175 }
176}