]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | //! Thread local storage |
c34b1796 | 2 | |
dfeec247 | 3 | #![unstable(feature = "thread_local_internals", issue = "none")] |
1a4d82fc | 4 | |
1b1a35ee XL |
5 | #[cfg(all(test, not(target_os = "emscripten")))] |
6 | mod tests; | |
7 | ||
8 | #[cfg(test)] | |
9 | mod dynamic_tests; | |
10 | ||
5e7ed085 | 11 | use crate::cell::{Cell, RefCell}; |
416331ca | 12 | use crate::error::Error; |
532ac7d7 | 13 | use crate::fmt; |
1a4d82fc JJ |
14 | |
15 | /// A thread local storage key which owns its contents. | |
16 | /// | |
17 | /// This key uses the fastest possible implementation available to it for the | |
7cac9316 XL |
18 | /// target platform. It is instantiated with the [`thread_local!`] macro and the |
19 | /// primary method is the [`with`] method. | |
1a4d82fc | 20 | /// |
7cac9316 | 21 | /// The [`with`] method yields a reference to the contained value which cannot be |
bd371182 | 22 | /// sent across threads or escape the given closure. |
1a4d82fc | 23 | /// |
04454e1e FG |
24 | /// [`thread_local!`]: crate::thread_local |
25 | /// | |
1a4d82fc JJ |
26 | /// # Initialization and Destruction |
27 | /// | |
7cac9316 XL |
28 | /// Initialization is dynamically performed on the first call to [`with`] |
29 | /// within a thread, and values that implement [`Drop`] get destructed when a | |
8bb4bdeb | 30 | /// thread exits. Some caveats apply, which are explained below. |
1a4d82fc | 31 | /// |
ea8adc8c XL |
32 | /// A `LocalKey`'s initializer cannot recursively depend on itself, and using |
33 | /// a `LocalKey` in this way will cause the initializer to infinitely recurse | |
34 | /// on the first call to `with`. | |
35 | /// | |
c34b1796 | 36 | /// # Examples |
1a4d82fc JJ |
37 | /// |
38 | /// ``` | |
39 | /// use std::cell::RefCell; | |
85aaf69f | 40 | /// use std::thread; |
1a4d82fc | 41 | /// |
c34b1796 | 42 | /// thread_local!(static FOO: RefCell<u32> = RefCell::new(1)); |
1a4d82fc JJ |
43 | /// |
44 | /// FOO.with(|f| { | |
45 | /// assert_eq!(*f.borrow(), 1); | |
46 | /// *f.borrow_mut() = 2; | |
47 | /// }); | |
48 | /// | |
49 | /// // each thread starts out with the initial value of 1 | |
532ac7d7 | 50 | /// let t = thread::spawn(move|| { |
1a4d82fc JJ |
51 | /// FOO.with(|f| { |
52 | /// assert_eq!(*f.borrow(), 1); | |
53 | /// *f.borrow_mut() = 3; | |
54 | /// }); | |
55 | /// }); | |
56 | /// | |
532ac7d7 XL |
57 | /// // wait for the thread to complete and bail out on panic |
58 | /// t.join().unwrap(); | |
59 | /// | |
1a4d82fc JJ |
60 | /// // we retain our original value of 2 despite the child thread |
61 | /// FOO.with(|f| { | |
62 | /// assert_eq!(*f.borrow(), 2); | |
63 | /// }); | |
64 | /// ``` | |
7453a54e SL |
65 | /// |
66 | /// # Platform-specific behavior | |
67 | /// | |
68 | /// Note that a "best effort" is made to ensure that destructors for types | |
a7813a04 | 69 | /// stored in thread local storage are run, but not all platforms can guarantee |
7453a54e SL |
70 | /// that destructors will be run for all types in thread local storage. For |
71 | /// example, there are a number of known caveats where destructors are not run: | |
72 | /// | |
73 | /// 1. On Unix systems when pthread-based TLS is being used, destructors will | |
74 | /// not be run for TLS values on the main thread when it exits. Note that the | |
75 | /// application will exit immediately after the main thread exits as well. | |
76 | /// 2. On all platforms it's possible for TLS to re-initialize other TLS slots | |
77 | /// during destruction. Some platforms ensure that this cannot happen | |
78 | /// infinitely by preventing re-initialization of any slot that has been | |
79 | /// destroyed, but not all platforms have this guard. Those platforms that do | |
80 | /// not guard typically have a synthetic limit after which point no more | |
81 | /// destructors are run. | |
a2a8927a XL |
82 | /// 3. When the process exits on Windows systems, TLS destructors may only be |
83 | /// run on the thread that causes the process to exit. This is because the | |
84 | /// other threads may be forcibly terminated. | |
7cac9316 | 85 | /// |
a2a8927a XL |
86 | /// ## Synchronization in thread-local destructors |
87 | /// | |
88 | /// On Windows, synchronization operations (such as [`JoinHandle::join`]) in | |
89 | /// thread local destructors are prone to deadlocks and so should be avoided. | |
90 | /// This is because the [loader lock] is held while a destructor is run. The | |
91 | /// lock is acquired whenever a thread starts or exits or when a DLL is loaded | |
92 | /// or unloaded. Therefore these events are blocked for as long as a thread | |
93 | /// local destructor is running. | |
94 | /// | |
95 | /// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices | |
96 | /// [`JoinHandle::join`]: crate::thread::JoinHandle::join | |
3dfed10e | 97 | /// [`with`]: LocalKey::with |
2b03887a | 98 | #[cfg_attr(not(test), rustc_diagnostic_item = "LocalKey")] |
85aaf69f | 99 | #[stable(feature = "rust1", since = "1.0.0")] |
9cc50fc6 SL |
100 | pub struct LocalKey<T: 'static> { |
101 | // This outer `LocalKey<T>` type is what's going to be stored in statics, | |
102 | // but actual data inside will sometimes be tagged with #[thread_local]. | |
103 | // It's not valid for a true static to reference a #[thread_local] static, | |
104 | // so we get around that by exposing an accessor through a layer of function | |
105 | // indirection (this thunk). | |
1a4d82fc | 106 | // |
9cc50fc6 SL |
107 | // Note that the thunk is itself unsafe because the returned lifetime of the |
108 | // slot where data lives, `'static`, is not actually valid. The lifetime | |
3b2f2976 | 109 | // here is actually slightly shorter than the currently running thread! |
9cc50fc6 SL |
110 | // |
111 | // Although this is an extra layer of indirection, it should in theory be | |
112 | // trivially devirtualizable by LLVM because the value of `inner` never | |
113 | // changes and the constant should be readonly within a crate. This mainly | |
114 | // only runs into problems when TLS statics are exported across crates. | |
5e7ed085 | 115 | inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, |
1a4d82fc JJ |
116 | } |
117 | ||
8bb4bdeb | 118 | #[stable(feature = "std_debug", since = "1.16.0")] |
32a655c1 | 119 | impl<T: 'static> fmt::Debug for LocalKey<T> { |
532ac7d7 | 120 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 121 | f.debug_struct("LocalKey").finish_non_exhaustive() |
32a655c1 SL |
122 | } |
123 | } | |
124 | ||
7cac9316 | 125 | /// Declare a new thread local storage key of type [`std::thread::LocalKey`]. |
62682a34 | 126 | /// |
3157f602 XL |
127 | /// # Syntax |
128 | /// | |
129 | /// The macro wraps any number of static declarations and makes them thread local. | |
041b39d2 | 130 | /// Publicity and attributes for each static are allowed. Example: |
3157f602 XL |
131 | /// |
132 | /// ``` | |
133 | /// use std::cell::RefCell; | |
134 | /// thread_local! { | |
135 | /// pub static FOO: RefCell<u32> = RefCell::new(1); | |
136 | /// | |
137 | /// #[allow(unused)] | |
138 | /// static BAR: RefCell<f32> = RefCell::new(1.0); | |
139 | /// } | |
140 | /// # fn main() {} | |
141 | /// ``` | |
142 | /// | |
3dfed10e | 143 | /// See [`LocalKey` documentation][`std::thread::LocalKey`] for more |
62682a34 | 144 | /// information. |
7cac9316 | 145 | /// |
3dfed10e | 146 | /// [`std::thread::LocalKey`]: crate::thread::LocalKey |
1a4d82fc | 147 | #[macro_export] |
62682a34 | 148 | #[stable(feature = "rust1", since = "1.0.0")] |
5099ac24 | 149 | #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")] |
532ac7d7 | 150 | #[allow_internal_unstable(thread_local_internals)] |
041b39d2 XL |
151 | macro_rules! thread_local { |
152 | // empty (base case for the recursion) | |
153 | () => {}; | |
154 | ||
cdc7bbd5 XL |
155 | ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => ( |
156 | $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); | |
157 | $crate::thread_local!($($rest)*); | |
158 | ); | |
159 | ||
160 | ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => ( | |
161 | $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init); | |
162 | ); | |
163 | ||
041b39d2 XL |
164 | // process multiple declarations |
165 | ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( | |
a1dfa0c6 XL |
166 | $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init); |
167 | $crate::thread_local!($($rest)*); | |
041b39d2 XL |
168 | ); |
169 | ||
170 | // handle a single declaration | |
171 | ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( | |
a1dfa0c6 | 172 | $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init); |
041b39d2 XL |
173 | ); |
174 | } | |
175 | ||
041b39d2 | 176 | #[doc(hidden)] |
dfeec247 | 177 | #[unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")] |
041b39d2 | 178 | #[macro_export] |
532ac7d7 | 179 | #[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)] |
ea8adc8c | 180 | #[allow_internal_unsafe] |
041b39d2 | 181 | macro_rules! __thread_local_inner { |
cdc7bbd5 XL |
182 | // used to generate the `LocalKey` value for const-initialized thread locals |
183 | (@key $t:ty, const $init:expr) => {{ | |
17df50a5 | 184 | #[cfg_attr(not(windows), inline)] // see comments below |
04454e1e | 185 | #[deny(unsafe_op_in_unsafe_fn)] |
5e7ed085 FG |
186 | unsafe fn __getit( |
187 | _init: $crate::option::Option<&mut $crate::option::Option<$t>>, | |
188 | ) -> $crate::option::Option<&'static $t> { | |
3c0e092e | 189 | const INIT_EXPR: $t = $init; |
cdc7bbd5 XL |
190 | |
191 | // wasm without atomics maps directly to `static mut`, and dtors | |
192 | // aren't implemented because thread dtors aren't really a thing | |
193 | // on wasm right now | |
194 | // | |
195 | // FIXME(#84224) this should come after the `target_thread_local` | |
196 | // block. | |
3c0e092e | 197 | #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] |
cdc7bbd5 | 198 | { |
3c0e092e | 199 | static mut VAL: $t = INIT_EXPR; |
04454e1e | 200 | unsafe { $crate::option::Option::Some(&VAL) } |
cdc7bbd5 XL |
201 | } |
202 | ||
203 | // If the platform has support for `#[thread_local]`, use it. | |
204 | #[cfg(all( | |
205 | target_thread_local, | |
3c0e092e | 206 | not(all(target_family = "wasm", not(target_feature = "atomics"))), |
cdc7bbd5 XL |
207 | ))] |
208 | { | |
3c0e092e XL |
209 | #[thread_local] |
210 | static mut VAL: $t = INIT_EXPR; | |
211 | ||
cdc7bbd5 XL |
212 | // If a dtor isn't needed we can do something "very raw" and |
213 | // just get going. | |
214 | if !$crate::mem::needs_drop::<$t>() { | |
cdc7bbd5 | 215 | unsafe { |
5e7ed085 | 216 | return $crate::option::Option::Some(&VAL) |
cdc7bbd5 XL |
217 | } |
218 | } | |
219 | ||
cdc7bbd5 XL |
220 | // 0 == dtor not registered |
221 | // 1 == dtor registered, dtor not run | |
222 | // 2 == dtor registered and is running or has run | |
223 | #[thread_local] | |
5e7ed085 | 224 | static mut STATE: $crate::primitive::u8 = 0; |
cdc7bbd5 | 225 | |
5e7ed085 | 226 | unsafe extern "C" fn destroy(ptr: *mut $crate::primitive::u8) { |
cdc7bbd5 XL |
227 | let ptr = ptr as *mut $t; |
228 | ||
229 | unsafe { | |
5e7ed085 | 230 | $crate::debug_assert_eq!(STATE, 1); |
cdc7bbd5 XL |
231 | STATE = 2; |
232 | $crate::ptr::drop_in_place(ptr); | |
233 | } | |
234 | } | |
235 | ||
236 | unsafe { | |
237 | match STATE { | |
238 | // 0 == we haven't registered a destructor, so do | |
239 | // so now. | |
240 | 0 => { | |
241 | $crate::thread::__FastLocalKeyInner::<$t>::register_dtor( | |
5e7ed085 | 242 | $crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8, |
cdc7bbd5 XL |
243 | destroy, |
244 | ); | |
245 | STATE = 1; | |
5e7ed085 | 246 | $crate::option::Option::Some(&VAL) |
cdc7bbd5 XL |
247 | } |
248 | // 1 == the destructor is registered and the value | |
249 | // is valid, so return the pointer. | |
5e7ed085 | 250 | 1 => $crate::option::Option::Some(&VAL), |
cdc7bbd5 XL |
251 | // otherwise the destructor has already run, so we |
252 | // can't give access. | |
5e7ed085 | 253 | _ => $crate::option::Option::None, |
cdc7bbd5 XL |
254 | } |
255 | } | |
256 | } | |
257 | ||
258 | // On platforms without `#[thread_local]` we fall back to the | |
259 | // same implementation as below for os thread locals. | |
260 | #[cfg(all( | |
261 | not(target_thread_local), | |
3c0e092e | 262 | not(all(target_family = "wasm", not(target_feature = "atomics"))), |
cdc7bbd5 XL |
263 | ))] |
264 | { | |
265 | #[inline] | |
3c0e092e | 266 | const fn __init() -> $t { INIT_EXPR } |
cdc7bbd5 XL |
267 | static __KEY: $crate::thread::__OsLocalKeyInner<$t> = |
268 | $crate::thread::__OsLocalKeyInner::new(); | |
269 | #[allow(unused_unsafe)] | |
5e7ed085 FG |
270 | unsafe { |
271 | __KEY.get(move || { | |
272 | if let $crate::option::Option::Some(init) = _init { | |
273 | if let $crate::option::Option::Some(value) = init.take() { | |
274 | return value; | |
275 | } else if $crate::cfg!(debug_assertions) { | |
276 | $crate::unreachable!("missing initial value"); | |
277 | } | |
278 | } | |
279 | __init() | |
280 | }) | |
281 | } | |
cdc7bbd5 XL |
282 | } |
283 | } | |
284 | ||
285 | unsafe { | |
286 | $crate::thread::LocalKey::new(__getit) | |
287 | } | |
288 | }}; | |
289 | ||
290 | // used to generate the `LocalKey` value for `thread_local!` | |
60c5eb7d | 291 | (@key $t:ty, $init:expr) => { |
ea8adc8c XL |
292 | { |
293 | #[inline] | |
041b39d2 XL |
294 | fn __init() -> $t { $init } |
295 | ||
17df50a5 XL |
296 | // When reading this function you might ask "why is this inlined |
297 | // everywhere other than Windows?", and that's a very reasonable | |
298 | // question to ask. The short story is that it segfaults rustc if | |
299 | // this function is inlined. The longer story is that Windows looks | |
300 | // to not support `extern` references to thread locals across DLL | |
301 | // boundaries. This appears to at least not be supported in the ABI | |
302 | // that LLVM implements. | |
303 | // | |
304 | // Because of this we never inline on Windows, but we do inline on | |
305 | // other platforms (where external references to thread locals | |
306 | // across DLLs are supported). A better fix for this would be to | |
307 | // inline this function on Windows, but only for "statically linked" | |
308 | // components. For example if two separately compiled rlibs end up | |
309 | // getting linked into a DLL then it's fine to inline this function | |
310 | // across that boundary. It's only not fine to inline this function | |
311 | // across a DLL boundary. Unfortunately rustc doesn't currently | |
312 | // have this sort of logic available in an attribute, and it's not | |
313 | // clear that rustc is even equipped to answer this (it's more of a | |
314 | // Cargo question kinda). This means that, unfortunately, Windows | |
315 | // gets the pessimistic path for now where it's never inlined. | |
316 | // | |
317 | // The issue of "should enable on Windows sometimes" is #84933 | |
318 | #[cfg_attr(not(windows), inline)] | |
5e7ed085 FG |
319 | unsafe fn __getit( |
320 | init: $crate::option::Option<&mut $crate::option::Option<$t>>, | |
321 | ) -> $crate::option::Option<&'static $t> { | |
3c0e092e | 322 | #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] |
83c7162d XL |
323 | static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = |
324 | $crate::thread::__StaticLocalKeyInner::new(); | |
325 | ||
041b39d2 | 326 | #[thread_local] |
0bf4aa26 XL |
327 | #[cfg(all( |
328 | target_thread_local, | |
3c0e092e | 329 | not(all(target_family = "wasm", not(target_feature = "atomics"))), |
0bf4aa26 | 330 | ))] |
041b39d2 XL |
331 | static __KEY: $crate::thread::__FastLocalKeyInner<$t> = |
332 | $crate::thread::__FastLocalKeyInner::new(); | |
333 | ||
0bf4aa26 XL |
334 | #[cfg(all( |
335 | not(target_thread_local), | |
3c0e092e | 336 | not(all(target_family = "wasm", not(target_feature = "atomics"))), |
0bf4aa26 | 337 | ))] |
041b39d2 XL |
338 | static __KEY: $crate::thread::__OsLocalKeyInner<$t> = |
339 | $crate::thread::__OsLocalKeyInner::new(); | |
340 | ||
3dfed10e XL |
341 | // FIXME: remove the #[allow(...)] marker when macros don't |
342 | // raise warning for missing/extraneous unsafe blocks anymore. | |
343 | // See https://github.com/rust-lang/rust/issues/74838. | |
344 | #[allow(unused_unsafe)] | |
5e7ed085 FG |
345 | unsafe { |
346 | __KEY.get(move || { | |
347 | if let $crate::option::Option::Some(init) = init { | |
348 | if let $crate::option::Option::Some(value) = init.take() { | |
349 | return value; | |
350 | } else if $crate::cfg!(debug_assertions) { | |
351 | $crate::unreachable!("missing default value"); | |
352 | } | |
353 | } | |
354 | __init() | |
355 | }) | |
356 | } | |
041b39d2 XL |
357 | } |
358 | ||
3b2f2976 | 359 | unsafe { |
dc9dc135 | 360 | $crate::thread::LocalKey::new(__getit) |
3b2f2976 | 361 | } |
ea8adc8c XL |
362 | } |
363 | }; | |
cdc7bbd5 | 364 | ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { |
ea8adc8c | 365 | $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = |
cdc7bbd5 | 366 | $crate::__thread_local_inner!(@key $t, $($init)*); |
041b39d2 XL |
367 | } |
368 | } | |
369 | ||
041b39d2 | 370 | /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with). |
0531ce1d | 371 | #[stable(feature = "thread_local_try_with", since = "1.26.0")] |
136023e0 | 372 | #[non_exhaustive] |
416331ca | 373 | #[derive(Clone, Copy, Eq, PartialEq)] |
136023e0 | 374 | pub struct AccessError; |
041b39d2 | 375 | |
0531ce1d | 376 | #[stable(feature = "thread_local_try_with", since = "1.26.0")] |
041b39d2 | 377 | impl fmt::Debug for AccessError { |
532ac7d7 | 378 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
379 | f.debug_struct("AccessError").finish() |
380 | } | |
381 | } | |
382 | ||
0531ce1d | 383 | #[stable(feature = "thread_local_try_with", since = "1.26.0")] |
041b39d2 | 384 | impl fmt::Display for AccessError { |
532ac7d7 | 385 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
041b39d2 XL |
386 | fmt::Display::fmt("already destroyed", f) |
387 | } | |
388 | } | |
389 | ||
416331ca XL |
390 | #[stable(feature = "thread_local_try_with", since = "1.26.0")] |
391 | impl Error for AccessError {} | |
392 | ||
c34b1796 | 393 | impl<T: 'static> LocalKey<T> { |
62682a34 | 394 | #[doc(hidden)] |
60c5eb7d XL |
395 | #[unstable( |
396 | feature = "thread_local_internals", | |
397 | reason = "recently added to create a key", | |
dfeec247 | 398 | issue = "none" |
60c5eb7d | 399 | )] |
1b1a35ee | 400 | #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] |
5e7ed085 FG |
401 | pub const unsafe fn new( |
402 | inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, | |
403 | ) -> LocalKey<T> { | |
60c5eb7d | 404 | LocalKey { inner } |
62682a34 SL |
405 | } |
406 | ||
9346a6ac | 407 | /// Acquires a reference to the value in this TLS key. |
1a4d82fc JJ |
408 | /// |
409 | /// This will lazily initialize the value if this thread has not referenced | |
410 | /// this key yet. | |
411 | /// | |
412 | /// # Panics | |
413 | /// | |
414 | /// This function will `panic!()` if the key currently has its | |
415 | /// destructor running, and it **may** panic if the destructor has | |
416 | /// previously been run for this thread. | |
85aaf69f | 417 | #[stable(feature = "rust1", since = "1.0.0")] |
1a4d82fc | 418 | pub fn with<F, R>(&'static self, f: F) -> R |
60c5eb7d XL |
419 | where |
420 | F: FnOnce(&T) -> R, | |
421 | { | |
422 | self.try_with(f).expect( | |
423 | "cannot access a Thread Local Storage value \ | |
424 | during or after destruction", | |
425 | ) | |
1a4d82fc JJ |
426 | } |
427 | ||
041b39d2 XL |
428 | /// Acquires a reference to the value in this TLS key. |
429 | /// | |
430 | /// This will lazily initialize the value if this thread has not referenced | |
431 | /// this key yet. If the key has been destroyed (which may happen if this is called | |
29967ef6 | 432 | /// in a destructor), this function will return an [`AccessError`]. |
041b39d2 XL |
433 | /// |
434 | /// # Panics | |
435 | /// | |
436 | /// This function will still `panic!()` if the key is uninitialized and the | |
437 | /// key's initializer panics. | |
0531ce1d | 438 | #[stable(feature = "thread_local_try_with", since = "1.26.0")] |
ba9703b0 | 439 | #[inline] |
041b39d2 | 440 | pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError> |
0531ce1d XL |
441 | where |
442 | F: FnOnce(&T) -> R, | |
443 | { | |
041b39d2 | 444 | unsafe { |
5e7ed085 | 445 | let thread_local = (self.inner)(None).ok_or(AccessError)?; |
dc9dc135 XL |
446 | Ok(f(thread_local)) |
447 | } | |
448 | } | |
5e7ed085 FG |
449 | |
450 | /// Acquires a reference to the value in this TLS key, initializing it with | |
451 | /// `init` if it wasn't already initialized on this thread. | |
452 | /// | |
453 | /// If `init` was used to initialize the thread local variable, `None` is | |
454 | /// passed as the first argument to `f`. If it was already initialized, | |
455 | /// `Some(init)` is passed to `f`. | |
456 | /// | |
457 | /// # Panics | |
458 | /// | |
459 | /// This function will panic if the key currently has its destructor | |
460 | /// running, and it **may** panic if the destructor has previously been run | |
461 | /// for this thread. | |
462 | fn initialize_with<F, R>(&'static self, init: T, f: F) -> R | |
463 | where | |
464 | F: FnOnce(Option<T>, &T) -> R, | |
465 | { | |
466 | unsafe { | |
467 | let mut init = Some(init); | |
468 | let reference = (self.inner)(Some(&mut init)).expect( | |
469 | "cannot access a Thread Local Storage value \ | |
470 | during or after destruction", | |
471 | ); | |
472 | f(init, reference) | |
473 | } | |
474 | } | |
475 | } | |
476 | ||
477 | impl<T: 'static> LocalKey<Cell<T>> { | |
478 | /// Sets or initializes the contained value. | |
479 | /// | |
480 | /// Unlike the other methods, this will *not* run the lazy initializer of | |
481 | /// the thread local. Instead, it will be directly initialized with the | |
482 | /// given value if it wasn't initialized yet. | |
483 | /// | |
484 | /// # Panics | |
485 | /// | |
486 | /// Panics if the key currently has its destructor running, | |
487 | /// and it **may** panic if the destructor has previously been run for this thread. | |
488 | /// | |
489 | /// # Examples | |
490 | /// | |
491 | /// ``` | |
492 | /// #![feature(local_key_cell_methods)] | |
493 | /// use std::cell::Cell; | |
494 | /// | |
495 | /// thread_local! { | |
496 | /// static X: Cell<i32> = panic!("!"); | |
497 | /// } | |
498 | /// | |
499 | /// // Calling X.get() here would result in a panic. | |
500 | /// | |
501 | /// X.set(123); // But X.set() is fine, as it skips the initializer above. | |
502 | /// | |
503 | /// assert_eq!(X.get(), 123); | |
504 | /// ``` | |
505 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
506 | pub fn set(&'static self, value: T) { | |
507 | self.initialize_with(Cell::new(value), |value, cell| { | |
508 | if let Some(value) = value { | |
509 | // The cell was already initialized, so `value` wasn't used to | |
510 | // initialize it. So we overwrite the current value with the | |
511 | // new one instead. | |
512 | cell.set(value.into_inner()); | |
513 | } | |
514 | }); | |
515 | } | |
516 | ||
517 | /// Returns a copy of the contained value. | |
518 | /// | |
519 | /// This will lazily initialize the value if this thread has not referenced | |
520 | /// this key yet. | |
521 | /// | |
522 | /// # Panics | |
523 | /// | |
524 | /// Panics if the key currently has its destructor running, | |
525 | /// and it **may** panic if the destructor has previously been run for this thread. | |
526 | /// | |
527 | /// # Examples | |
528 | /// | |
529 | /// ``` | |
530 | /// #![feature(local_key_cell_methods)] | |
531 | /// use std::cell::Cell; | |
532 | /// | |
533 | /// thread_local! { | |
534 | /// static X: Cell<i32> = Cell::new(1); | |
535 | /// } | |
536 | /// | |
537 | /// assert_eq!(X.get(), 1); | |
538 | /// ``` | |
539 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
540 | pub fn get(&'static self) -> T | |
541 | where | |
542 | T: Copy, | |
543 | { | |
544 | self.with(|cell| cell.get()) | |
545 | } | |
546 | ||
547 | /// Takes the contained value, leaving `Default::default()` in its place. | |
548 | /// | |
549 | /// This will lazily initialize the value if this thread has not referenced | |
550 | /// this key yet. | |
551 | /// | |
552 | /// # Panics | |
553 | /// | |
554 | /// Panics if the key currently has its destructor running, | |
555 | /// and it **may** panic if the destructor has previously been run for this thread. | |
556 | /// | |
557 | /// # Examples | |
558 | /// | |
559 | /// ``` | |
560 | /// #![feature(local_key_cell_methods)] | |
561 | /// use std::cell::Cell; | |
562 | /// | |
563 | /// thread_local! { | |
564 | /// static X: Cell<Option<i32>> = Cell::new(Some(1)); | |
565 | /// } | |
566 | /// | |
567 | /// assert_eq!(X.take(), Some(1)); | |
568 | /// assert_eq!(X.take(), None); | |
569 | /// ``` | |
570 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
571 | pub fn take(&'static self) -> T | |
572 | where | |
573 | T: Default, | |
574 | { | |
575 | self.with(|cell| cell.take()) | |
576 | } | |
577 | ||
578 | /// Replaces the contained value, returning the old value. | |
579 | /// | |
580 | /// This will lazily initialize the value if this thread has not referenced | |
581 | /// this key yet. | |
582 | /// | |
583 | /// # Panics | |
584 | /// | |
585 | /// Panics if the key currently has its destructor running, | |
586 | /// and it **may** panic if the destructor has previously been run for this thread. | |
587 | /// | |
588 | /// # Examples | |
589 | /// | |
590 | /// ``` | |
591 | /// #![feature(local_key_cell_methods)] | |
592 | /// use std::cell::Cell; | |
593 | /// | |
594 | /// thread_local! { | |
595 | /// static X: Cell<i32> = Cell::new(1); | |
596 | /// } | |
597 | /// | |
598 | /// assert_eq!(X.replace(2), 1); | |
599 | /// assert_eq!(X.replace(3), 2); | |
600 | /// ``` | |
601 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
602 | pub fn replace(&'static self, value: T) -> T { | |
603 | self.with(|cell| cell.replace(value)) | |
604 | } | |
605 | } | |
606 | ||
607 | impl<T: 'static> LocalKey<RefCell<T>> { | |
608 | /// Acquires a reference to the contained value. | |
609 | /// | |
610 | /// This will lazily initialize the value if this thread has not referenced | |
611 | /// this key yet. | |
612 | /// | |
613 | /// # Panics | |
614 | /// | |
615 | /// Panics if the value is currently mutably borrowed. | |
616 | /// | |
617 | /// Panics if the key currently has its destructor running, | |
618 | /// and it **may** panic if the destructor has previously been run for this thread. | |
619 | /// | |
620 | /// # Example | |
621 | /// | |
622 | /// ``` | |
623 | /// #![feature(local_key_cell_methods)] | |
624 | /// use std::cell::RefCell; | |
625 | /// | |
626 | /// thread_local! { | |
627 | /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); | |
628 | /// } | |
629 | /// | |
630 | /// X.with_borrow(|v| assert!(v.is_empty())); | |
631 | /// ``` | |
632 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
633 | pub fn with_borrow<F, R>(&'static self, f: F) -> R | |
634 | where | |
635 | F: FnOnce(&T) -> R, | |
636 | { | |
637 | self.with(|cell| f(&cell.borrow())) | |
638 | } | |
639 | ||
640 | /// Acquires a mutable reference to the contained value. | |
641 | /// | |
642 | /// This will lazily initialize the value if this thread has not referenced | |
643 | /// this key yet. | |
644 | /// | |
645 | /// # Panics | |
646 | /// | |
647 | /// Panics if the value is currently borrowed. | |
648 | /// | |
649 | /// Panics if the key currently has its destructor running, | |
650 | /// and it **may** panic if the destructor has previously been run for this thread. | |
651 | /// | |
652 | /// # Example | |
653 | /// | |
654 | /// ``` | |
655 | /// #![feature(local_key_cell_methods)] | |
656 | /// use std::cell::RefCell; | |
657 | /// | |
658 | /// thread_local! { | |
659 | /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); | |
660 | /// } | |
661 | /// | |
662 | /// X.with_borrow_mut(|v| v.push(1)); | |
663 | /// | |
664 | /// X.with_borrow(|v| assert_eq!(*v, vec![1])); | |
665 | /// ``` | |
666 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
667 | pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R | |
668 | where | |
669 | F: FnOnce(&mut T) -> R, | |
670 | { | |
671 | self.with(|cell| f(&mut cell.borrow_mut())) | |
672 | } | |
673 | ||
674 | /// Sets or initializes the contained value. | |
675 | /// | |
676 | /// Unlike the other methods, this will *not* run the lazy initializer of | |
677 | /// the thread local. Instead, it will be directly initialized with the | |
678 | /// given value if it wasn't initialized yet. | |
679 | /// | |
680 | /// # Panics | |
681 | /// | |
682 | /// Panics if the value is currently borrowed. | |
683 | /// | |
684 | /// Panics if the key currently has its destructor running, | |
685 | /// and it **may** panic if the destructor has previously been run for this thread. | |
686 | /// | |
687 | /// # Examples | |
688 | /// | |
689 | /// ``` | |
690 | /// #![feature(local_key_cell_methods)] | |
691 | /// use std::cell::RefCell; | |
692 | /// | |
693 | /// thread_local! { | |
694 | /// static X: RefCell<Vec<i32>> = panic!("!"); | |
695 | /// } | |
696 | /// | |
697 | /// // Calling X.with() here would result in a panic. | |
698 | /// | |
699 | /// X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above. | |
700 | /// | |
701 | /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); | |
702 | /// ``` | |
703 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
704 | pub fn set(&'static self, value: T) { | |
705 | self.initialize_with(RefCell::new(value), |value, cell| { | |
706 | if let Some(value) = value { | |
707 | // The cell was already initialized, so `value` wasn't used to | |
708 | // initialize it. So we overwrite the current value with the | |
709 | // new one instead. | |
710 | *cell.borrow_mut() = value.into_inner(); | |
711 | } | |
712 | }); | |
713 | } | |
714 | ||
715 | /// Takes the contained value, leaving `Default::default()` in its place. | |
716 | /// | |
717 | /// This will lazily initialize the value if this thread has not referenced | |
718 | /// this key yet. | |
719 | /// | |
720 | /// # Panics | |
721 | /// | |
722 | /// Panics if the value is currently borrowed. | |
723 | /// | |
724 | /// Panics if the key currently has its destructor running, | |
725 | /// and it **may** panic if the destructor has previously been run for this thread. | |
726 | /// | |
727 | /// # Examples | |
728 | /// | |
729 | /// ``` | |
730 | /// #![feature(local_key_cell_methods)] | |
731 | /// use std::cell::RefCell; | |
732 | /// | |
733 | /// thread_local! { | |
734 | /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); | |
735 | /// } | |
736 | /// | |
737 | /// X.with_borrow_mut(|v| v.push(1)); | |
738 | /// | |
739 | /// let a = X.take(); | |
740 | /// | |
741 | /// assert_eq!(a, vec![1]); | |
742 | /// | |
743 | /// X.with_borrow(|v| assert!(v.is_empty())); | |
744 | /// ``` | |
745 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
746 | pub fn take(&'static self) -> T | |
747 | where | |
748 | T: Default, | |
749 | { | |
750 | self.with(|cell| cell.take()) | |
751 | } | |
752 | ||
753 | /// Replaces the contained value, returning the old value. | |
754 | /// | |
755 | /// # Panics | |
756 | /// | |
757 | /// Panics if the value is currently borrowed. | |
758 | /// | |
759 | /// Panics if the key currently has its destructor running, | |
760 | /// and it **may** panic if the destructor has previously been run for this thread. | |
761 | /// | |
762 | /// # Examples | |
763 | /// | |
764 | /// ``` | |
765 | /// #![feature(local_key_cell_methods)] | |
766 | /// use std::cell::RefCell; | |
767 | /// | |
768 | /// thread_local! { | |
769 | /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); | |
770 | /// } | |
771 | /// | |
772 | /// let prev = X.replace(vec![1, 2, 3]); | |
773 | /// assert!(prev.is_empty()); | |
774 | /// | |
775 | /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); | |
776 | /// ``` | |
777 | #[unstable(feature = "local_key_cell_methods", issue = "92122")] | |
778 | pub fn replace(&'static self, value: T) -> T { | |
779 | self.with(|cell| cell.replace(value)) | |
780 | } | |
dc9dc135 XL |
781 | } |
782 | ||
783 | mod lazy { | |
784 | use crate::cell::UnsafeCell; | |
dc9dc135 | 785 | use crate::hint; |
60c5eb7d | 786 | use crate::mem; |
dc9dc135 XL |
787 | |
788 | pub struct LazyKeyInner<T> { | |
789 | inner: UnsafeCell<Option<T>>, | |
790 | } | |
791 | ||
792 | impl<T> LazyKeyInner<T> { | |
793 | pub const fn new() -> LazyKeyInner<T> { | |
60c5eb7d | 794 | LazyKeyInner { inner: UnsafeCell::new(None) } |
dc9dc135 XL |
795 | } |
796 | ||
797 | pub unsafe fn get(&self) -> Option<&'static T> { | |
1b1a35ee XL |
798 | // SAFETY: The caller must ensure no reference is ever handed out to |
799 | // the inner cell nor mutable reference to the Option<T> inside said | |
800 | // cell. This make it safe to hand a reference, though the lifetime | |
801 | // of 'static is itself unsafe, making the get method unsafe. | |
802 | unsafe { (*self.inner.get()).as_ref() } | |
dc9dc135 XL |
803 | } |
804 | ||
1b1a35ee XL |
805 | /// The caller must ensure that no reference is active: this method |
806 | /// needs unique access. | |
dc9dc135 XL |
807 | pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T { |
808 | // Execute the initialization up front, *then* move it into our slot, | |
809 | // just in case initialization fails. | |
810 | let value = init(); | |
811 | let ptr = self.inner.get(); | |
812 | ||
1b1a35ee XL |
813 | // SAFETY: |
814 | // | |
dc9dc135 XL |
815 | // note that this can in theory just be `*ptr = Some(value)`, but due to |
816 | // the compiler will currently codegen that pattern with something like: | |
817 | // | |
818 | // ptr::drop_in_place(ptr) | |
819 | // ptr::write(ptr, Some(value)) | |
820 | // | |
821 | // Due to this pattern it's possible for the destructor of the value in | |
822 | // `ptr` (e.g., if this is being recursively initialized) to re-access | |
823 | // TLS, in which case there will be a `&` and `&mut` pointer to the same | |
824 | // value (an aliasing violation). To avoid setting the "I'm running a | |
825 | // destructor" flag we just use `mem::replace` which should sequence the | |
826 | // operations a little differently and make this safe to call. | |
1b1a35ee XL |
827 | // |
828 | // The precondition also ensures that we are the only one accessing | |
829 | // `self` at the moment so replacing is fine. | |
830 | unsafe { | |
831 | let _ = mem::replace(&mut *ptr, Some(value)); | |
832 | } | |
833 | ||
834 | // SAFETY: With the call to `mem::replace` it is guaranteed there is | |
835 | // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked` | |
836 | // will never be reached. | |
837 | unsafe { | |
838 | // After storing `Some` we want to get a reference to the contents of | |
839 | // what we just stored. While we could use `unwrap` here and it should | |
840 | // always work it empirically doesn't seem to always get optimized away, | |
841 | // which means that using something like `try_with` can pull in | |
842 | // panicking code and cause a large size bloat. | |
843 | match *ptr { | |
844 | Some(ref x) => x, | |
845 | None => hint::unreachable_unchecked(), | |
846 | } | |
dc9dc135 XL |
847 | } |
848 | } | |
849 | ||
1b1a35ee XL |
850 | /// The other methods hand out references while taking &self. |
851 | /// As such, callers of this method must ensure no `&` and `&mut` are | |
852 | /// available and used at the same time. | |
dc9dc135 XL |
853 | #[allow(unused)] |
854 | pub unsafe fn take(&mut self) -> Option<T> { | |
1b1a35ee XL |
855 | // SAFETY: See doc comment for this method. |
856 | unsafe { (*self.inner.get()).take() } | |
041b39d2 XL |
857 | } |
858 | } | |
859 | } | |
860 | ||
3c0e092e | 861 | /// On some targets like wasm there's no threads, so no need to generate |
83c7162d XL |
862 | /// thread locals and we can instead just use plain statics! |
863 | #[doc(hidden)] | |
3c0e092e | 864 | #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] |
83c7162d | 865 | pub mod statik { |
dc9dc135 | 866 | use super::lazy::LazyKeyInner; |
532ac7d7 | 867 | use crate::fmt; |
83c7162d XL |
868 | |
869 | pub struct Key<T> { | |
dc9dc135 | 870 | inner: LazyKeyInner<T>, |
83c7162d XL |
871 | } |
872 | ||
60c5eb7d | 873 | unsafe impl<T> Sync for Key<T> {} |
83c7162d XL |
874 | |
875 | impl<T> fmt::Debug for Key<T> { | |
532ac7d7 | 876 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 877 | f.debug_struct("Key").finish_non_exhaustive() |
83c7162d XL |
878 | } |
879 | } | |
880 | ||
881 | impl<T> Key<T> { | |
882 | pub const fn new() -> Key<T> { | |
60c5eb7d | 883 | Key { inner: LazyKeyInner::new() } |
83c7162d XL |
884 | } |
885 | ||
5e7ed085 | 886 | pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> { |
1b1a35ee XL |
887 | // SAFETY: The caller must ensure no reference is ever handed out to |
888 | // the inner cell nor mutable reference to the Option<T> inside said | |
889 | // cell. This make it safe to hand a reference, though the lifetime | |
890 | // of 'static is itself unsafe, making the get method unsafe. | |
891 | let value = unsafe { | |
892 | match self.inner.get() { | |
893 | Some(ref value) => value, | |
894 | None => self.inner.initialize(init), | |
895 | } | |
dc9dc135 | 896 | }; |
1b1a35ee | 897 | |
dc9dc135 | 898 | Some(value) |
83c7162d XL |
899 | } |
900 | } | |
901 | } | |
902 | ||
041b39d2 | 903 | #[doc(hidden)] |
2b03887a | 904 | #[cfg(all(target_thread_local, not(all(target_family = "wasm", not(target_feature = "atomics"))),))] |
041b39d2 | 905 | pub mod fast { |
dc9dc135 XL |
906 | use super::lazy::LazyKeyInner; |
907 | use crate::cell::Cell; | |
3dfed10e | 908 | use crate::sys::thread_local_dtor::register_dtor; |
9c376795 | 909 | use crate::{fmt, mem, panic}; |
041b39d2 | 910 | |
dc9dc135 XL |
911 | #[derive(Copy, Clone)] |
912 | enum DtorState { | |
913 | Unregistered, | |
914 | Registered, | |
915 | RunningOrHasRun, | |
916 | } | |
917 | ||
918 | // This data structure has been carefully constructed so that the fast path | |
919 | // only contains one branch on x86. That optimization is necessary to avoid | |
920 | // duplicated tls lookups on OSX. | |
921 | // | |
922 | // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 | |
041b39d2 | 923 | pub struct Key<T> { |
dc9dc135 XL |
924 | // If `LazyKeyInner::get` returns `None`, that indicates either: |
925 | // * The value has never been initialized | |
926 | // * The value is being recursively initialized | |
927 | // * The value has already been destroyed or is being destroyed | |
928 | // To determine which kind of `None`, check `dtor_state`. | |
929 | // | |
930 | // This is very optimizer friendly for the fast path - initialized but | |
931 | // not yet dropped. | |
932 | inner: LazyKeyInner<T>, | |
041b39d2 XL |
933 | |
934 | // Metadata to keep track of the state of the destructor. Remember that | |
dc9dc135 XL |
935 | // this variable is thread-local, not global. |
936 | dtor_state: Cell<DtorState>, | |
041b39d2 XL |
937 | } |
938 | ||
939 | impl<T> fmt::Debug for Key<T> { | |
532ac7d7 | 940 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 941 | f.debug_struct("Key").finish_non_exhaustive() |
041b39d2 XL |
942 | } |
943 | } | |
944 | ||
041b39d2 XL |
945 | impl<T> Key<T> { |
946 | pub const fn new() -> Key<T> { | |
60c5eb7d | 947 | Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) } |
041b39d2 XL |
948 | } |
949 | ||
a2a8927a | 950 | // note that this is just a publicly-callable function only for the |
cdc7bbd5 | 951 | // const-initialized form of thread locals, basically a way to call the |
9c376795 | 952 | // free `register_dtor` function defined elsewhere in std. |
cdc7bbd5 XL |
953 | pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { |
954 | unsafe { | |
955 | register_dtor(a, dtor); | |
956 | } | |
957 | } | |
958 | ||
dc9dc135 | 959 | pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> { |
1b1a35ee | 960 | // SAFETY: See the definitions of `LazyKeyInner::get` and |
a2a8927a | 961 | // `try_initialize` for more information. |
1b1a35ee XL |
962 | // |
963 | // The caller must ensure no mutable references are ever active to | |
964 | // the inner cell or the inner T when this is called. | |
965 | // The `try_initialize` is dependant on the passed `init` function | |
966 | // for this. | |
967 | unsafe { | |
968 | match self.inner.get() { | |
969 | Some(val) => Some(val), | |
970 | None => self.try_initialize(init), | |
971 | } | |
041b39d2 | 972 | } |
041b39d2 XL |
973 | } |
974 | ||
dc9dc135 XL |
975 | // `try_initialize` is only called once per fast thread local variable, |
976 | // except in corner cases where thread_local dtors reference other | |
977 | // thread_local's, or it is being recursively initialized. | |
978 | // | |
979 | // Macos: Inlining this function can cause two `tlv_get_addr` calls to | |
1b1a35ee | 980 | // be performed for every call to `Key::get`. |
dc9dc135 | 981 | // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 |
1b1a35ee | 982 | #[inline(never)] |
dc9dc135 | 983 | unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> { |
1b1a35ee XL |
984 | // SAFETY: See comment above (this function doc). |
985 | if !mem::needs_drop::<T>() || unsafe { self.try_register_dtor() } { | |
04454e1e | 986 | // SAFETY: See comment above (this function doc). |
1b1a35ee | 987 | Some(unsafe { self.inner.initialize(init) }) |
dc9dc135 XL |
988 | } else { |
989 | None | |
041b39d2 | 990 | } |
dc9dc135 | 991 | } |
041b39d2 | 992 | |
dc9dc135 XL |
993 | // `try_register_dtor` is only called once per fast thread local |
994 | // variable, except in corner cases where thread_local dtors reference | |
995 | // other thread_local's, or it is being recursively initialized. | |
996 | unsafe fn try_register_dtor(&self) -> bool { | |
997 | match self.dtor_state.get() { | |
998 | DtorState::Unregistered => { | |
1b1a35ee XL |
999 | // SAFETY: dtor registration happens before initialization. |
1000 | // Passing `self` as a pointer while using `destroy_value<T>` | |
1001 | // is safe because the function will build a pointer to a | |
1002 | // Key<T>, which is the type of self and so find the correct | |
1003 | // size. | |
1004 | unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::<T>) }; | |
dc9dc135 XL |
1005 | self.dtor_state.set(DtorState::Registered); |
1006 | true | |
1007 | } | |
1008 | DtorState::Registered => { | |
1009 | // recursively initialized | |
1010 | true | |
1011 | } | |
60c5eb7d | 1012 | DtorState::RunningOrHasRun => false, |
dc9dc135 | 1013 | } |
041b39d2 XL |
1014 | } |
1015 | } | |
1016 | ||
60c5eb7d | 1017 | unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) { |
041b39d2 | 1018 | let ptr = ptr as *mut Key<T>; |
041b39d2 | 1019 | |
1b1a35ee XL |
1020 | // SAFETY: |
1021 | // | |
1022 | // The pointer `ptr` has been built just above and comes from | |
1023 | // `try_register_dtor` where it is originally a Key<T> coming from `self`, | |
1024 | // making it non-NUL and of the correct type. | |
1025 | // | |
dc9dc135 XL |
1026 | // Right before we run the user destructor be sure to set the |
1027 | // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This | |
1028 | // causes future calls to `get` to run `try_initialize_drop` again, | |
1029 | // which will now fail, and return `None`. | |
9c376795 FG |
1030 | // |
1031 | // Wrap the call in a catch to ensure unwinding is caught in the event | |
1032 | // a panic takes place in a destructor. | |
1033 | if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { | |
1b1a35ee XL |
1034 | let value = (*ptr).inner.take(); |
1035 | (*ptr).dtor_state.set(DtorState::RunningOrHasRun); | |
1036 | drop(value); | |
9c376795 FG |
1037 | })) { |
1038 | rtabort!("thread local panicked on drop"); | |
1b1a35ee | 1039 | } |
041b39d2 | 1040 | } |
1a4d82fc JJ |
1041 | } |
1042 | ||
d9579d0f | 1043 | #[doc(hidden)] |
2b03887a FG |
1044 | #[cfg(all( |
1045 | not(target_thread_local), | |
1046 | not(all(target_family = "wasm", not(target_feature = "atomics"))), | |
1047 | ))] | |
9cc50fc6 | 1048 | pub mod os { |
dc9dc135 XL |
1049 | use super::lazy::LazyKeyInner; |
1050 | use crate::cell::Cell; | |
3dfed10e | 1051 | use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; |
9c376795 | 1052 | use crate::{fmt, marker, panic, ptr}; |
1a4d82fc | 1053 | |
f2b60f7d FG |
1054 | /// Use a regular global static to store this key; the state provided will then be |
1055 | /// thread-local. | |
1a4d82fc | 1056 | pub struct Key<T> { |
1a4d82fc | 1057 | // OS-TLS key that we'll use to key off. |
62682a34 SL |
1058 | os: OsStaticKey, |
1059 | marker: marker::PhantomData<Cell<T>>, | |
1a4d82fc JJ |
1060 | } |
1061 | ||
32a655c1 | 1062 | impl<T> fmt::Debug for Key<T> { |
532ac7d7 | 1063 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
cdc7bbd5 | 1064 | f.debug_struct("Key").finish_non_exhaustive() |
32a655c1 SL |
1065 | } |
1066 | } | |
1067 | ||
60c5eb7d | 1068 | unsafe impl<T> Sync for Key<T> {} |
1a4d82fc JJ |
1069 | |
1070 | struct Value<T: 'static> { | |
dc9dc135 | 1071 | inner: LazyKeyInner<T>, |
1a4d82fc | 1072 | key: &'static Key<T>, |
1a4d82fc JJ |
1073 | } |
1074 | ||
62682a34 | 1075 | impl<T: 'static> Key<T> { |
1b1a35ee | 1076 | #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] |
62682a34 | 1077 | pub const fn new() -> Key<T> { |
60c5eb7d | 1078 | Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData } |
1a4d82fc JJ |
1079 | } |
1080 | ||
1b1a35ee XL |
1081 | /// It is a requirement for the caller to ensure that no mutable |
1082 | /// reference is active when this method is called. | |
5e7ed085 | 1083 | pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { |
1b1a35ee XL |
1084 | // SAFETY: See the documentation for this method. |
1085 | let ptr = unsafe { self.os.get() as *mut Value<T> }; | |
5e7ed085 | 1086 | if ptr.addr() > 1 { |
1b1a35ee XL |
1087 | // SAFETY: the check ensured the pointer is safe (its destructor |
1088 | // is not running) + it is coming from a trusted source (self). | |
1089 | if let Some(ref value) = unsafe { (*ptr).inner.get() } { | |
e74abb32 | 1090 | return Some(value); |
1a4d82fc | 1091 | } |
dc9dc135 | 1092 | } |
1b1a35ee XL |
1093 | // SAFETY: At this point we are sure we have no value and so |
1094 | // initializing (or trying to) is safe. | |
1095 | unsafe { self.try_initialize(init) } | |
dc9dc135 XL |
1096 | } |
1097 | ||
1098 | // `try_initialize` is only called once per os thread local variable, | |
1099 | // except in corner cases where thread_local dtors reference other | |
1100 | // thread_local's, or it is being recursively initialized. | |
5e7ed085 | 1101 | unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { |
1b1a35ee XL |
1102 | // SAFETY: No mutable references are ever handed out meaning getting |
1103 | // the value is ok. | |
1104 | let ptr = unsafe { self.os.get() as *mut Value<T> }; | |
5e7ed085 | 1105 | if ptr.addr() == 1 { |
dc9dc135 | 1106 | // destructor is running |
60c5eb7d | 1107 | return None; |
7453a54e | 1108 | } |
3b2f2976 | 1109 | |
dc9dc135 XL |
1110 | let ptr = if ptr.is_null() { |
1111 | // If the lookup returned null, we haven't initialized our own | |
1112 | // local copy, so do that now. | |
9ffffee4 | 1113 | let ptr = Box::into_raw(Box::new(Value { inner: LazyKeyInner::new(), key: self })); |
1b1a35ee XL |
1114 | // SAFETY: At this point we are sure there is no value inside |
1115 | // ptr so setting it will not affect anyone else. | |
1116 | unsafe { | |
1117 | self.os.set(ptr as *mut u8); | |
1118 | } | |
dc9dc135 XL |
1119 | ptr |
1120 | } else { | |
1121 | // recursive initialization | |
1122 | ptr | |
3b2f2976 | 1123 | }; |
dc9dc135 | 1124 | |
1b1a35ee XL |
1125 | // SAFETY: ptr has been ensured as non-NUL just above an so can be |
1126 | // dereferenced safely. | |
1127 | unsafe { Some((*ptr).inner.initialize(init)) } | |
1a4d82fc JJ |
1128 | } |
1129 | } | |
1130 | ||
60c5eb7d | 1131 | unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) { |
1b1a35ee XL |
1132 | // SAFETY: |
1133 | // | |
17df50a5 | 1134 | // The OS TLS ensures that this key contains a null value when this |
1a4d82fc JJ |
1135 | // destructor starts to run. We set it back to a sentinel value of 1 to |
1136 | // ensure that any future calls to `get` for this thread will return | |
1137 | // `None`. | |
1138 | // | |
1139 | // Note that to prevent an infinite loop we reset it back to null right | |
1140 | // before we return from the destructor ourselves. | |
9c376795 FG |
1141 | // |
1142 | // Wrap the call in a catch to ensure unwinding is caught in the event | |
1143 | // a panic takes place in a destructor. | |
1144 | if let Err(_) = panic::catch_unwind(|| unsafe { | |
1b1a35ee XL |
1145 | let ptr = Box::from_raw(ptr as *mut Value<T>); |
1146 | let key = ptr.key; | |
5e7ed085 | 1147 | key.os.set(ptr::invalid_mut(1)); |
1b1a35ee XL |
1148 | drop(ptr); |
1149 | key.os.set(ptr::null_mut()); | |
9c376795 FG |
1150 | }) { |
1151 | rtabort!("thread local panicked on drop"); | |
1a4d82fc | 1152 | } |
1a4d82fc JJ |
1153 | } |
1154 | } |