]> git.proxmox.com Git - rustc.git/blame - library/std/src/thread/local.rs
New upstream version 1.69.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
5e7ed085 11use crate::cell::{Cell, RefCell};
416331ca 12use crate::error::Error;
532ac7d7 13use 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
100pub 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 119impl<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
151macro_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 181macro_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 374pub struct AccessError;
041b39d2 375
0531ce1d 376#[stable(feature = "thread_local_try_with", since = "1.26.0")]
041b39d2 377impl 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 384impl 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")]
391impl Error for AccessError {}
392
c34b1796 393impl<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
477impl<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
607impl<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
783mod 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 865pub 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 905pub 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 1048pub 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}