]> git.proxmox.com Git - rustc.git/blame - library/std/src/thread/local.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / library / std / src / thread / local.rs
CommitLineData
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")))]
6mod tests;
7
8#[cfg(test)]
9mod dynamic_tests;
10
416331ca 11use crate::error::Error;
532ac7d7 12use crate::fmt;
1a4d82fc
JJ
13
14/// A thread local storage key which owns its contents.
15///
16/// This key uses the fastest possible implementation available to it for the
7cac9316
XL
17/// target platform. It is instantiated with the [`thread_local!`] macro and the
18/// primary method is the [`with`] method.
1a4d82fc 19///
7cac9316 20/// The [`with`] method yields a reference to the contained value which cannot be
bd371182 21/// sent across threads or escape the given closure.
1a4d82fc
JJ
22///
23/// # Initialization and Destruction
24///
7cac9316
XL
25/// Initialization is dynamically performed on the first call to [`with`]
26/// within a thread, and values that implement [`Drop`] get destructed when a
8bb4bdeb 27/// thread exits. Some caveats apply, which are explained below.
1a4d82fc 28///
ea8adc8c
XL
29/// A `LocalKey`'s initializer cannot recursively depend on itself, and using
30/// a `LocalKey` in this way will cause the initializer to infinitely recurse
31/// on the first call to `with`.
32///
c34b1796 33/// # Examples
1a4d82fc
JJ
34///
35/// ```
36/// use std::cell::RefCell;
85aaf69f 37/// use std::thread;
1a4d82fc 38///
c34b1796 39/// thread_local!(static FOO: RefCell<u32> = RefCell::new(1));
1a4d82fc
JJ
40///
41/// FOO.with(|f| {
42/// assert_eq!(*f.borrow(), 1);
43/// *f.borrow_mut() = 2;
44/// });
45///
46/// // each thread starts out with the initial value of 1
532ac7d7 47/// let t = thread::spawn(move|| {
1a4d82fc
JJ
48/// FOO.with(|f| {
49/// assert_eq!(*f.borrow(), 1);
50/// *f.borrow_mut() = 3;
51/// });
52/// });
53///
532ac7d7
XL
54/// // wait for the thread to complete and bail out on panic
55/// t.join().unwrap();
56///
1a4d82fc
JJ
57/// // we retain our original value of 2 despite the child thread
58/// FOO.with(|f| {
59/// assert_eq!(*f.borrow(), 2);
60/// });
61/// ```
7453a54e
SL
62///
63/// # Platform-specific behavior
64///
65/// Note that a "best effort" is made to ensure that destructors for types
a7813a04 66/// stored in thread local storage are run, but not all platforms can guarantee
7453a54e
SL
67/// that destructors will be run for all types in thread local storage. For
68/// example, there are a number of known caveats where destructors are not run:
69///
70/// 1. On Unix systems when pthread-based TLS is being used, destructors will
71/// not be run for TLS values on the main thread when it exits. Note that the
72/// application will exit immediately after the main thread exits as well.
73/// 2. On all platforms it's possible for TLS to re-initialize other TLS slots
74/// during destruction. Some platforms ensure that this cannot happen
75/// infinitely by preventing re-initialization of any slot that has been
76/// destroyed, but not all platforms have this guard. Those platforms that do
77/// not guard typically have a synthetic limit after which point no more
78/// destructors are run.
a2a8927a
XL
79/// 3. When the process exits on Windows systems, TLS destructors may only be
80/// run on the thread that causes the process to exit. This is because the
81/// other threads may be forcibly terminated.
7cac9316 82///
a2a8927a
XL
83/// ## Synchronization in thread-local destructors
84///
85/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
86/// thread local destructors are prone to deadlocks and so should be avoided.
87/// This is because the [loader lock] is held while a destructor is run. The
88/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
89/// or unloaded. Therefore these events are blocked for as long as a thread
90/// local destructor is running.
91///
92/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
93/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
3dfed10e 94/// [`with`]: LocalKey::with
85aaf69f 95#[stable(feature = "rust1", since = "1.0.0")]
9cc50fc6
SL
96pub struct LocalKey<T: 'static> {
97 // This outer `LocalKey<T>` type is what's going to be stored in statics,
98 // but actual data inside will sometimes be tagged with #[thread_local].
99 // It's not valid for a true static to reference a #[thread_local] static,
100 // so we get around that by exposing an accessor through a layer of function
101 // indirection (this thunk).
1a4d82fc 102 //
9cc50fc6
SL
103 // Note that the thunk is itself unsafe because the returned lifetime of the
104 // slot where data lives, `'static`, is not actually valid. The lifetime
3b2f2976 105 // here is actually slightly shorter than the currently running thread!
9cc50fc6
SL
106 //
107 // Although this is an extra layer of indirection, it should in theory be
108 // trivially devirtualizable by LLVM because the value of `inner` never
109 // changes and the constant should be readonly within a crate. This mainly
110 // only runs into problems when TLS statics are exported across crates.
dc9dc135 111 inner: unsafe fn() -> Option<&'static T>,
1a4d82fc
JJ
112}
113
8bb4bdeb 114#[stable(feature = "std_debug", since = "1.16.0")]
32a655c1 115impl<T: 'static> fmt::Debug for LocalKey<T> {
532ac7d7 116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cdc7bbd5 117 f.debug_struct("LocalKey").finish_non_exhaustive()
32a655c1
SL
118 }
119}
120
7cac9316 121/// Declare a new thread local storage key of type [`std::thread::LocalKey`].
62682a34 122///
3157f602
XL
123/// # Syntax
124///
125/// The macro wraps any number of static declarations and makes them thread local.
041b39d2 126/// Publicity and attributes for each static are allowed. Example:
3157f602
XL
127///
128/// ```
129/// use std::cell::RefCell;
130/// thread_local! {
131/// pub static FOO: RefCell<u32> = RefCell::new(1);
132///
133/// #[allow(unused)]
134/// static BAR: RefCell<f32> = RefCell::new(1.0);
135/// }
136/// # fn main() {}
137/// ```
138///
3dfed10e 139/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
62682a34 140/// information.
7cac9316 141///
3dfed10e 142/// [`std::thread::LocalKey`]: crate::thread::LocalKey
1a4d82fc 143#[macro_export]
62682a34 144#[stable(feature = "rust1", since = "1.0.0")]
5099ac24 145#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
532ac7d7 146#[allow_internal_unstable(thread_local_internals)]
041b39d2
XL
147macro_rules! thread_local {
148 // empty (base case for the recursion)
149 () => {};
150
cdc7bbd5
XL
151 ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
152 $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
153 $crate::thread_local!($($rest)*);
154 );
155
156 ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
157 $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
158 );
159
041b39d2
XL
160 // process multiple declarations
161 ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
a1dfa0c6
XL
162 $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
163 $crate::thread_local!($($rest)*);
041b39d2
XL
164 );
165
166 // handle a single declaration
167 ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
a1dfa0c6 168 $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
041b39d2
XL
169 );
170}
171
041b39d2 172#[doc(hidden)]
dfeec247 173#[unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
041b39d2 174#[macro_export]
532ac7d7 175#[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)]
ea8adc8c 176#[allow_internal_unsafe]
041b39d2 177macro_rules! __thread_local_inner {
cdc7bbd5
XL
178 // used to generate the `LocalKey` value for const-initialized thread locals
179 (@key $t:ty, const $init:expr) => {{
17df50a5 180 #[cfg_attr(not(windows), inline)] // see comments below
cdc7bbd5 181 unsafe fn __getit() -> $crate::option::Option<&'static $t> {
3c0e092e 182 const INIT_EXPR: $t = $init;
cdc7bbd5
XL
183
184 // wasm without atomics maps directly to `static mut`, and dtors
185 // aren't implemented because thread dtors aren't really a thing
186 // on wasm right now
187 //
188 // FIXME(#84224) this should come after the `target_thread_local`
189 // block.
3c0e092e 190 #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
cdc7bbd5 191 {
3c0e092e 192 static mut VAL: $t = INIT_EXPR;
cdc7bbd5
XL
193 Some(&VAL)
194 }
195
196 // If the platform has support for `#[thread_local]`, use it.
197 #[cfg(all(
198 target_thread_local,
3c0e092e 199 not(all(target_family = "wasm", not(target_feature = "atomics"))),
cdc7bbd5
XL
200 ))]
201 {
3c0e092e
XL
202 #[thread_local]
203 static mut VAL: $t = INIT_EXPR;
204
cdc7bbd5
XL
205 // If a dtor isn't needed we can do something "very raw" and
206 // just get going.
207 if !$crate::mem::needs_drop::<$t>() {
cdc7bbd5
XL
208 unsafe {
209 return Some(&VAL)
210 }
211 }
212
cdc7bbd5
XL
213 // 0 == dtor not registered
214 // 1 == dtor registered, dtor not run
215 // 2 == dtor registered and is running or has run
216 #[thread_local]
217 static mut STATE: u8 = 0;
218
219 unsafe extern "C" fn destroy(ptr: *mut u8) {
220 let ptr = ptr as *mut $t;
221
222 unsafe {
223 debug_assert_eq!(STATE, 1);
224 STATE = 2;
225 $crate::ptr::drop_in_place(ptr);
226 }
227 }
228
229 unsafe {
230 match STATE {
231 // 0 == we haven't registered a destructor, so do
232 // so now.
233 0 => {
234 $crate::thread::__FastLocalKeyInner::<$t>::register_dtor(
235 $crate::ptr::addr_of_mut!(VAL) as *mut u8,
236 destroy,
237 );
238 STATE = 1;
239 Some(&VAL)
240 }
241 // 1 == the destructor is registered and the value
242 // is valid, so return the pointer.
243 1 => Some(&VAL),
244 // otherwise the destructor has already run, so we
245 // can't give access.
246 _ => None,
247 }
248 }
249 }
250
251 // On platforms without `#[thread_local]` we fall back to the
252 // same implementation as below for os thread locals.
253 #[cfg(all(
254 not(target_thread_local),
3c0e092e 255 not(all(target_family = "wasm", not(target_feature = "atomics"))),
cdc7bbd5
XL
256 ))]
257 {
258 #[inline]
3c0e092e 259 const fn __init() -> $t { INIT_EXPR }
cdc7bbd5
XL
260 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
261 $crate::thread::__OsLocalKeyInner::new();
262 #[allow(unused_unsafe)]
263 unsafe { __KEY.get(__init) }
264 }
265 }
266
267 unsafe {
268 $crate::thread::LocalKey::new(__getit)
269 }
270 }};
271
272 // used to generate the `LocalKey` value for `thread_local!`
60c5eb7d 273 (@key $t:ty, $init:expr) => {
ea8adc8c
XL
274 {
275 #[inline]
041b39d2
XL
276 fn __init() -> $t { $init }
277
17df50a5
XL
278 // When reading this function you might ask "why is this inlined
279 // everywhere other than Windows?", and that's a very reasonable
280 // question to ask. The short story is that it segfaults rustc if
281 // this function is inlined. The longer story is that Windows looks
282 // to not support `extern` references to thread locals across DLL
283 // boundaries. This appears to at least not be supported in the ABI
284 // that LLVM implements.
285 //
286 // Because of this we never inline on Windows, but we do inline on
287 // other platforms (where external references to thread locals
288 // across DLLs are supported). A better fix for this would be to
289 // inline this function on Windows, but only for "statically linked"
290 // components. For example if two separately compiled rlibs end up
291 // getting linked into a DLL then it's fine to inline this function
292 // across that boundary. It's only not fine to inline this function
293 // across a DLL boundary. Unfortunately rustc doesn't currently
294 // have this sort of logic available in an attribute, and it's not
295 // clear that rustc is even equipped to answer this (it's more of a
296 // Cargo question kinda). This means that, unfortunately, Windows
297 // gets the pessimistic path for now where it's never inlined.
298 //
299 // The issue of "should enable on Windows sometimes" is #84933
300 #[cfg_attr(not(windows), inline)]
dc9dc135 301 unsafe fn __getit() -> $crate::option::Option<&'static $t> {
3c0e092e 302 #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
83c7162d
XL
303 static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
304 $crate::thread::__StaticLocalKeyInner::new();
305
041b39d2 306 #[thread_local]
0bf4aa26
XL
307 #[cfg(all(
308 target_thread_local,
3c0e092e 309 not(all(target_family = "wasm", not(target_feature = "atomics"))),
0bf4aa26 310 ))]
041b39d2
XL
311 static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
312 $crate::thread::__FastLocalKeyInner::new();
313
0bf4aa26
XL
314 #[cfg(all(
315 not(target_thread_local),
3c0e092e 316 not(all(target_family = "wasm", not(target_feature = "atomics"))),
0bf4aa26 317 ))]
041b39d2
XL
318 static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
319 $crate::thread::__OsLocalKeyInner::new();
320
3dfed10e
XL
321 // FIXME: remove the #[allow(...)] marker when macros don't
322 // raise warning for missing/extraneous unsafe blocks anymore.
323 // See https://github.com/rust-lang/rust/issues/74838.
324 #[allow(unused_unsafe)]
325 unsafe { __KEY.get(__init) }
041b39d2
XL
326 }
327
3b2f2976 328 unsafe {
dc9dc135 329 $crate::thread::LocalKey::new(__getit)
3b2f2976 330 }
ea8adc8c
XL
331 }
332 };
cdc7bbd5 333 ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
ea8adc8c 334 $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
cdc7bbd5 335 $crate::__thread_local_inner!(@key $t, $($init)*);
041b39d2
XL
336 }
337}
338
041b39d2 339/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
0531ce1d 340#[stable(feature = "thread_local_try_with", since = "1.26.0")]
136023e0 341#[non_exhaustive]
416331ca 342#[derive(Clone, Copy, Eq, PartialEq)]
136023e0 343pub struct AccessError;
041b39d2 344
0531ce1d 345#[stable(feature = "thread_local_try_with", since = "1.26.0")]
041b39d2 346impl fmt::Debug for AccessError {
532ac7d7 347 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
041b39d2
XL
348 f.debug_struct("AccessError").finish()
349 }
350}
351
0531ce1d 352#[stable(feature = "thread_local_try_with", since = "1.26.0")]
041b39d2 353impl fmt::Display for AccessError {
532ac7d7 354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
041b39d2
XL
355 fmt::Display::fmt("already destroyed", f)
356 }
357}
358
416331ca
XL
359#[stable(feature = "thread_local_try_with", since = "1.26.0")]
360impl Error for AccessError {}
361
c34b1796 362impl<T: 'static> LocalKey<T> {
62682a34 363 #[doc(hidden)]
60c5eb7d
XL
364 #[unstable(
365 feature = "thread_local_internals",
366 reason = "recently added to create a key",
dfeec247 367 issue = "none"
60c5eb7d 368 )]
1b1a35ee 369 #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
dc9dc135 370 pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> {
60c5eb7d 371 LocalKey { inner }
62682a34
SL
372 }
373
9346a6ac 374 /// Acquires a reference to the value in this TLS key.
1a4d82fc
JJ
375 ///
376 /// This will lazily initialize the value if this thread has not referenced
377 /// this key yet.
378 ///
379 /// # Panics
380 ///
381 /// This function will `panic!()` if the key currently has its
382 /// destructor running, and it **may** panic if the destructor has
383 /// previously been run for this thread.
85aaf69f 384 #[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 385 pub fn with<F, R>(&'static self, f: F) -> R
60c5eb7d
XL
386 where
387 F: FnOnce(&T) -> R,
388 {
389 self.try_with(f).expect(
390 "cannot access a Thread Local Storage value \
391 during or after destruction",
392 )
1a4d82fc
JJ
393 }
394
041b39d2
XL
395 /// Acquires a reference to the value in this TLS key.
396 ///
397 /// This will lazily initialize the value if this thread has not referenced
398 /// this key yet. If the key has been destroyed (which may happen if this is called
29967ef6 399 /// in a destructor), this function will return an [`AccessError`].
041b39d2
XL
400 ///
401 /// # Panics
402 ///
403 /// This function will still `panic!()` if the key is uninitialized and the
404 /// key's initializer panics.
0531ce1d 405 #[stable(feature = "thread_local_try_with", since = "1.26.0")]
ba9703b0 406 #[inline]
041b39d2 407 pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
0531ce1d
XL
408 where
409 F: FnOnce(&T) -> R,
410 {
041b39d2 411 unsafe {
136023e0 412 let thread_local = (self.inner)().ok_or(AccessError)?;
dc9dc135
XL
413 Ok(f(thread_local))
414 }
415 }
416}
417
418mod lazy {
419 use crate::cell::UnsafeCell;
dc9dc135 420 use crate::hint;
60c5eb7d 421 use crate::mem;
dc9dc135
XL
422
423 pub struct LazyKeyInner<T> {
424 inner: UnsafeCell<Option<T>>,
425 }
426
427 impl<T> LazyKeyInner<T> {
428 pub const fn new() -> LazyKeyInner<T> {
60c5eb7d 429 LazyKeyInner { inner: UnsafeCell::new(None) }
dc9dc135
XL
430 }
431
432 pub unsafe fn get(&self) -> Option<&'static T> {
1b1a35ee
XL
433 // SAFETY: The caller must ensure no reference is ever handed out to
434 // the inner cell nor mutable reference to the Option<T> inside said
435 // cell. This make it safe to hand a reference, though the lifetime
436 // of 'static is itself unsafe, making the get method unsafe.
437 unsafe { (*self.inner.get()).as_ref() }
dc9dc135
XL
438 }
439
1b1a35ee
XL
440 /// The caller must ensure that no reference is active: this method
441 /// needs unique access.
dc9dc135
XL
442 pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
443 // Execute the initialization up front, *then* move it into our slot,
444 // just in case initialization fails.
445 let value = init();
446 let ptr = self.inner.get();
447
1b1a35ee
XL
448 // SAFETY:
449 //
dc9dc135
XL
450 // note that this can in theory just be `*ptr = Some(value)`, but due to
451 // the compiler will currently codegen that pattern with something like:
452 //
453 // ptr::drop_in_place(ptr)
454 // ptr::write(ptr, Some(value))
455 //
456 // Due to this pattern it's possible for the destructor of the value in
457 // `ptr` (e.g., if this is being recursively initialized) to re-access
458 // TLS, in which case there will be a `&` and `&mut` pointer to the same
459 // value (an aliasing violation). To avoid setting the "I'm running a
460 // destructor" flag we just use `mem::replace` which should sequence the
461 // operations a little differently and make this safe to call.
1b1a35ee
XL
462 //
463 // The precondition also ensures that we are the only one accessing
464 // `self` at the moment so replacing is fine.
465 unsafe {
466 let _ = mem::replace(&mut *ptr, Some(value));
467 }
468
469 // SAFETY: With the call to `mem::replace` it is guaranteed there is
470 // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
471 // will never be reached.
472 unsafe {
473 // After storing `Some` we want to get a reference to the contents of
474 // what we just stored. While we could use `unwrap` here and it should
475 // always work it empirically doesn't seem to always get optimized away,
476 // which means that using something like `try_with` can pull in
477 // panicking code and cause a large size bloat.
478 match *ptr {
479 Some(ref x) => x,
480 None => hint::unreachable_unchecked(),
481 }
dc9dc135
XL
482 }
483 }
484
1b1a35ee
XL
485 /// The other methods hand out references while taking &self.
486 /// As such, callers of this method must ensure no `&` and `&mut` are
487 /// available and used at the same time.
dc9dc135
XL
488 #[allow(unused)]
489 pub unsafe fn take(&mut self) -> Option<T> {
1b1a35ee
XL
490 // SAFETY: See doc comment for this method.
491 unsafe { (*self.inner.get()).take() }
041b39d2
XL
492 }
493 }
494}
495
3c0e092e 496/// On some targets like wasm there's no threads, so no need to generate
83c7162d
XL
497/// thread locals and we can instead just use plain statics!
498#[doc(hidden)]
3c0e092e 499#[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
83c7162d 500pub mod statik {
dc9dc135 501 use super::lazy::LazyKeyInner;
532ac7d7 502 use crate::fmt;
83c7162d
XL
503
504 pub struct Key<T> {
dc9dc135 505 inner: LazyKeyInner<T>,
83c7162d
XL
506 }
507
60c5eb7d 508 unsafe impl<T> Sync for Key<T> {}
83c7162d
XL
509
510 impl<T> fmt::Debug for Key<T> {
532ac7d7 511 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cdc7bbd5 512 f.debug_struct("Key").finish_non_exhaustive()
83c7162d
XL
513 }
514 }
515
516 impl<T> Key<T> {
517 pub const fn new() -> Key<T> {
60c5eb7d 518 Key { inner: LazyKeyInner::new() }
83c7162d
XL
519 }
520
dc9dc135 521 pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> {
1b1a35ee
XL
522 // SAFETY: The caller must ensure no reference is ever handed out to
523 // the inner cell nor mutable reference to the Option<T> inside said
524 // cell. This make it safe to hand a reference, though the lifetime
525 // of 'static is itself unsafe, making the get method unsafe.
526 let value = unsafe {
527 match self.inner.get() {
528 Some(ref value) => value,
529 None => self.inner.initialize(init),
530 }
dc9dc135 531 };
1b1a35ee 532
dc9dc135 533 Some(value)
83c7162d
XL
534 }
535 }
536}
537
041b39d2
XL
538#[doc(hidden)]
539#[cfg(target_thread_local)]
540pub mod fast {
dc9dc135
XL
541 use super::lazy::LazyKeyInner;
542 use crate::cell::Cell;
532ac7d7
XL
543 use crate::fmt;
544 use crate::mem;
3dfed10e 545 use crate::sys::thread_local_dtor::register_dtor;
041b39d2 546
dc9dc135
XL
547 #[derive(Copy, Clone)]
548 enum DtorState {
549 Unregistered,
550 Registered,
551 RunningOrHasRun,
552 }
553
554 // This data structure has been carefully constructed so that the fast path
555 // only contains one branch on x86. That optimization is necessary to avoid
556 // duplicated tls lookups on OSX.
557 //
558 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
041b39d2 559 pub struct Key<T> {
dc9dc135
XL
560 // If `LazyKeyInner::get` returns `None`, that indicates either:
561 // * The value has never been initialized
562 // * The value is being recursively initialized
563 // * The value has already been destroyed or is being destroyed
564 // To determine which kind of `None`, check `dtor_state`.
565 //
566 // This is very optimizer friendly for the fast path - initialized but
567 // not yet dropped.
568 inner: LazyKeyInner<T>,
041b39d2
XL
569
570 // Metadata to keep track of the state of the destructor. Remember that
dc9dc135
XL
571 // this variable is thread-local, not global.
572 dtor_state: Cell<DtorState>,
041b39d2
XL
573 }
574
575 impl<T> fmt::Debug for Key<T> {
532ac7d7 576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cdc7bbd5 577 f.debug_struct("Key").finish_non_exhaustive()
041b39d2
XL
578 }
579 }
580
041b39d2
XL
581 impl<T> Key<T> {
582 pub const fn new() -> Key<T> {
60c5eb7d 583 Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) }
041b39d2
XL
584 }
585
a2a8927a 586 // note that this is just a publicly-callable function only for the
cdc7bbd5
XL
587 // const-initialized form of thread locals, basically a way to call the
588 // free `register_dtor` function defined elsewhere in libstd.
589 pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
590 unsafe {
591 register_dtor(a, dtor);
592 }
593 }
594
dc9dc135 595 pub unsafe fn get<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
1b1a35ee 596 // SAFETY: See the definitions of `LazyKeyInner::get` and
a2a8927a 597 // `try_initialize` for more information.
1b1a35ee
XL
598 //
599 // The caller must ensure no mutable references are ever active to
600 // the inner cell or the inner T when this is called.
601 // The `try_initialize` is dependant on the passed `init` function
602 // for this.
603 unsafe {
604 match self.inner.get() {
605 Some(val) => Some(val),
606 None => self.try_initialize(init),
607 }
041b39d2 608 }
041b39d2
XL
609 }
610
dc9dc135
XL
611 // `try_initialize` is only called once per fast thread local variable,
612 // except in corner cases where thread_local dtors reference other
613 // thread_local's, or it is being recursively initialized.
614 //
615 // Macos: Inlining this function can cause two `tlv_get_addr` calls to
1b1a35ee 616 // be performed for every call to `Key::get`.
dc9dc135 617 // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
1b1a35ee 618 #[inline(never)]
dc9dc135 619 unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
1b1a35ee
XL
620 // SAFETY: See comment above (this function doc).
621 if !mem::needs_drop::<T>() || unsafe { self.try_register_dtor() } {
622 // SAFETY: See comment above (his function doc).
623 Some(unsafe { self.inner.initialize(init) })
dc9dc135
XL
624 } else {
625 None
041b39d2 626 }
dc9dc135 627 }
041b39d2 628
dc9dc135
XL
629 // `try_register_dtor` is only called once per fast thread local
630 // variable, except in corner cases where thread_local dtors reference
631 // other thread_local's, or it is being recursively initialized.
632 unsafe fn try_register_dtor(&self) -> bool {
633 match self.dtor_state.get() {
634 DtorState::Unregistered => {
1b1a35ee
XL
635 // SAFETY: dtor registration happens before initialization.
636 // Passing `self` as a pointer while using `destroy_value<T>`
637 // is safe because the function will build a pointer to a
638 // Key<T>, which is the type of self and so find the correct
639 // size.
640 unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::<T>) };
dc9dc135
XL
641 self.dtor_state.set(DtorState::Registered);
642 true
643 }
644 DtorState::Registered => {
645 // recursively initialized
646 true
647 }
60c5eb7d 648 DtorState::RunningOrHasRun => false,
dc9dc135 649 }
041b39d2
XL
650 }
651 }
652
60c5eb7d 653 unsafe extern "C" fn destroy_value<T>(ptr: *mut u8) {
041b39d2 654 let ptr = ptr as *mut Key<T>;
041b39d2 655
1b1a35ee
XL
656 // SAFETY:
657 //
658 // The pointer `ptr` has been built just above and comes from
659 // `try_register_dtor` where it is originally a Key<T> coming from `self`,
660 // making it non-NUL and of the correct type.
661 //
dc9dc135
XL
662 // Right before we run the user destructor be sure to set the
663 // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
664 // causes future calls to `get` to run `try_initialize_drop` again,
665 // which will now fail, and return `None`.
1b1a35ee
XL
666 unsafe {
667 let value = (*ptr).inner.take();
668 (*ptr).dtor_state.set(DtorState::RunningOrHasRun);
669 drop(value);
670 }
041b39d2 671 }
1a4d82fc
JJ
672}
673
d9579d0f 674#[doc(hidden)]
9cc50fc6 675pub mod os {
dc9dc135
XL
676 use super::lazy::LazyKeyInner;
677 use crate::cell::Cell;
532ac7d7
XL
678 use crate::fmt;
679 use crate::marker;
680 use crate::ptr;
3dfed10e 681 use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
1a4d82fc 682
1a4d82fc 683 pub struct Key<T> {
1a4d82fc 684 // OS-TLS key that we'll use to key off.
62682a34
SL
685 os: OsStaticKey,
686 marker: marker::PhantomData<Cell<T>>,
1a4d82fc
JJ
687 }
688
32a655c1 689 impl<T> fmt::Debug for Key<T> {
532ac7d7 690 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cdc7bbd5 691 f.debug_struct("Key").finish_non_exhaustive()
32a655c1
SL
692 }
693 }
694
60c5eb7d 695 unsafe impl<T> Sync for Key<T> {}
1a4d82fc
JJ
696
697 struct Value<T: 'static> {
dc9dc135 698 inner: LazyKeyInner<T>,
1a4d82fc 699 key: &'static Key<T>,
1a4d82fc
JJ
700 }
701
62682a34 702 impl<T: 'static> Key<T> {
1b1a35ee 703 #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
62682a34 704 pub const fn new() -> Key<T> {
60c5eb7d 705 Key { os: OsStaticKey::new(Some(destroy_value::<T>)), marker: marker::PhantomData }
1a4d82fc
JJ
706 }
707
1b1a35ee
XL
708 /// It is a requirement for the caller to ensure that no mutable
709 /// reference is active when this method is called.
dc9dc135 710 pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> {
1b1a35ee
XL
711 // SAFETY: See the documentation for this method.
712 let ptr = unsafe { self.os.get() as *mut Value<T> };
dc9dc135 713 if ptr as usize > 1 {
1b1a35ee
XL
714 // SAFETY: the check ensured the pointer is safe (its destructor
715 // is not running) + it is coming from a trusted source (self).
716 if let Some(ref value) = unsafe { (*ptr).inner.get() } {
e74abb32 717 return Some(value);
1a4d82fc 718 }
dc9dc135 719 }
1b1a35ee
XL
720 // SAFETY: At this point we are sure we have no value and so
721 // initializing (or trying to) is safe.
722 unsafe { self.try_initialize(init) }
dc9dc135
XL
723 }
724
725 // `try_initialize` is only called once per os thread local variable,
726 // except in corner cases where thread_local dtors reference other
727 // thread_local's, or it is being recursively initialized.
728 unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> {
1b1a35ee
XL
729 // SAFETY: No mutable references are ever handed out meaning getting
730 // the value is ok.
731 let ptr = unsafe { self.os.get() as *mut Value<T> };
dc9dc135
XL
732 if ptr as usize == 1 {
733 // destructor is running
60c5eb7d 734 return None;
7453a54e 735 }
3b2f2976 736
dc9dc135
XL
737 let ptr = if ptr.is_null() {
738 // If the lookup returned null, we haven't initialized our own
739 // local copy, so do that now.
60c5eb7d 740 let ptr: Box<Value<T>> = box Value { inner: LazyKeyInner::new(), key: self };
dc9dc135 741 let ptr = Box::into_raw(ptr);
1b1a35ee
XL
742 // SAFETY: At this point we are sure there is no value inside
743 // ptr so setting it will not affect anyone else.
744 unsafe {
745 self.os.set(ptr as *mut u8);
746 }
dc9dc135
XL
747 ptr
748 } else {
749 // recursive initialization
750 ptr
3b2f2976 751 };
dc9dc135 752
1b1a35ee
XL
753 // SAFETY: ptr has been ensured as non-NUL just above an so can be
754 // dereferenced safely.
755 unsafe { Some((*ptr).inner.initialize(init)) }
1a4d82fc
JJ
756 }
757 }
758
60c5eb7d 759 unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
1b1a35ee
XL
760 // SAFETY:
761 //
17df50a5 762 // The OS TLS ensures that this key contains a null value when this
1a4d82fc
JJ
763 // destructor starts to run. We set it back to a sentinel value of 1 to
764 // ensure that any future calls to `get` for this thread will return
765 // `None`.
766 //
767 // Note that to prevent an infinite loop we reset it back to null right
768 // before we return from the destructor ourselves.
1b1a35ee
XL
769 unsafe {
770 let ptr = Box::from_raw(ptr as *mut Value<T>);
771 let key = ptr.key;
772 key.os.set(1 as *mut u8);
773 drop(ptr);
774 key.os.set(ptr::null_mut());
1a4d82fc 775 }
1a4d82fc
JJ
776 }
777}