std/thread/
local.rs

1//! Thread local storage
2
3#![unstable(feature = "thread_local_internals", issue = "none")]
4
5use crate::cell::{Cell, RefCell};
6use crate::error::Error;
7use crate::fmt;
8
9/// A thread local storage (TLS) key which owns its contents.
10///
11/// This key uses the fastest possible implementation available to it for the
12/// target platform. It is instantiated with the [`thread_local!`] macro and the
13/// primary method is the [`with`] method, though there are helpers to make
14/// working with [`Cell`] types easier.
15///
16/// The [`with`] method yields a reference to the contained value which cannot
17/// outlive the current thread or escape the given closure.
18///
19/// [`thread_local!`]: crate::thread_local
20///
21/// # Initialization and Destruction
22///
23/// Initialization is dynamically performed on the first call to a setter (e.g.
24/// [`with`]) within a thread, and values that implement [`Drop`] get
25/// destructed when a thread exits. Some platform-specific caveats apply, which
26/// are explained below.
27/// Note that, should the destructor panics, the whole process will be [aborted].
28///
29/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
30/// `LocalKey` in this way may cause panics, aborts or infinite recursion on
31/// the first call to `with`.
32///
33/// [aborted]: crate::process::abort
34///
35/// # Single-thread Synchronization
36///
37/// Though there is no potential race with other threads, it is still possible to
38/// obtain multiple references to the thread-local data in different places on
39/// the call stack. For this reason, only shared (`&T`) references may be obtained.
40///
41/// To allow obtaining an exclusive mutable reference (`&mut T`), typically a
42/// [`Cell`] or [`RefCell`] is used (see the [`std::cell`] for more information
43/// on how exactly this works). To make this easier there are specialized
44/// implementations for [`LocalKey<Cell<T>>`] and [`LocalKey<RefCell<T>>`].
45///
46/// [`std::cell`]: `crate::cell`
47/// [`LocalKey<Cell<T>>`]: struct.LocalKey.html#impl-LocalKey<Cell<T>>
48/// [`LocalKey<RefCell<T>>`]: struct.LocalKey.html#impl-LocalKey<RefCell<T>>
49///
50///
51/// # Examples
52///
53/// ```
54/// use std::cell::Cell;
55/// use std::thread;
56///
57/// // explicit `const {}` block enables more efficient initialization
58/// thread_local!(static FOO: Cell<u32> = const { Cell::new(1) });
59///
60/// assert_eq!(FOO.get(), 1);
61/// FOO.set(2);
62///
63/// // each thread starts out with the initial value of 1
64/// let t = thread::spawn(move || {
65///     assert_eq!(FOO.get(), 1);
66///     FOO.set(3);
67/// });
68///
69/// // wait for the thread to complete and bail out on panic
70/// t.join().unwrap();
71///
72/// // we retain our original value of 2 despite the child thread
73/// assert_eq!(FOO.get(), 2);
74/// ```
75///
76/// # Platform-specific behavior
77///
78/// Note that a "best effort" is made to ensure that destructors for types
79/// stored in thread local storage are run, but not all platforms can guarantee
80/// that destructors will be run for all types in thread local storage. For
81/// example, there are a number of known caveats where destructors are not run:
82///
83/// 1. On Unix systems when pthread-based TLS is being used, destructors will
84///    not be run for TLS values on the main thread when it exits. Note that the
85///    application will exit immediately after the main thread exits as well.
86/// 2. On all platforms it's possible for TLS to re-initialize other TLS slots
87///    during destruction. Some platforms ensure that this cannot happen
88///    infinitely by preventing re-initialization of any slot that has been
89///    destroyed, but not all platforms have this guard. Those platforms that do
90///    not guard typically have a synthetic limit after which point no more
91///    destructors are run.
92/// 3. When the process exits on Windows systems, TLS destructors may only be
93///    run on the thread that causes the process to exit. This is because the
94///    other threads may be forcibly terminated.
95///
96/// ## Synchronization in thread-local destructors
97///
98/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
99/// thread local destructors are prone to deadlocks and so should be avoided.
100/// This is because the [loader lock] is held while a destructor is run. The
101/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
102/// or unloaded. Therefore these events are blocked for as long as a thread
103/// local destructor is running.
104///
105/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
106/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
107/// [`with`]: LocalKey::with
108#[cfg_attr(not(test), rustc_diagnostic_item = "LocalKey")]
109#[stable(feature = "rust1", since = "1.0.0")]
110pub struct LocalKey<T: 'static> {
111    // This outer `LocalKey<T>` type is what's going to be stored in statics,
112    // but actual data inside will sometimes be tagged with #[thread_local].
113    // It's not valid for a true static to reference a #[thread_local] static,
114    // so we get around that by exposing an accessor through a layer of function
115    // indirection (this thunk).
116    //
117    // Note that the thunk is itself unsafe because the returned lifetime of the
118    // slot where data lives, `'static`, is not actually valid. The lifetime
119    // here is actually slightly shorter than the currently running thread!
120    //
121    // Although this is an extra layer of indirection, it should in theory be
122    // trivially devirtualizable by LLVM because the value of `inner` never
123    // changes and the constant should be readonly within a crate. This mainly
124    // only runs into problems when TLS statics are exported across crates.
125    inner: fn(Option<&mut Option<T>>) -> *const T,
126}
127
128#[stable(feature = "std_debug", since = "1.16.0")]
129impl<T: 'static> fmt::Debug for LocalKey<T> {
130    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131        f.debug_struct("LocalKey").finish_non_exhaustive()
132    }
133}
134
135/// Declare a new thread local storage key of type [`std::thread::LocalKey`].
136///
137/// # Syntax
138///
139/// The macro wraps any number of static declarations and makes them thread local.
140/// Publicity and attributes for each static are allowed. Example:
141///
142/// ```
143/// use std::cell::{Cell, RefCell};
144///
145/// thread_local! {
146///     pub static FOO: Cell<u32> = const { Cell::new(1) };
147///
148///     static BAR: RefCell<Vec<f32>> = RefCell::new(vec![1.0, 2.0]);
149/// }
150///
151/// assert_eq!(FOO.get(), 1);
152/// BAR.with_borrow(|v| assert_eq!(v[1], 2.0));
153/// ```
154///
155/// Note that only shared references (`&T`) to the inner data may be obtained, so a
156/// type such as [`Cell`] or [`RefCell`] is typically used to allow mutating access.
157///
158/// This macro supports a special `const {}` syntax that can be used
159/// when the initialization expression can be evaluated as a constant.
160/// This can enable a more efficient thread local implementation that
161/// can avoid lazy initialization. For types that do not
162/// [need to be dropped][crate::mem::needs_drop], this can enable an
163/// even more efficient implementation that does not need to
164/// track any additional state.
165///
166/// ```
167/// use std::cell::RefCell;
168///
169/// thread_local! {
170///     pub static FOO: RefCell<Vec<u32>> = const { RefCell::new(Vec::new()) };
171/// }
172///
173/// FOO.with_borrow(|v| assert_eq!(v.len(), 0));
174/// ```
175///
176/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
177/// information.
178///
179/// [`std::thread::LocalKey`]: crate::thread::LocalKey
180#[macro_export]
181#[stable(feature = "rust1", since = "1.0.0")]
182#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
183#[allow_internal_unstable(thread_local_internals)]
184macro_rules! thread_local {
185    // empty (base case for the recursion)
186    () => {};
187
188    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => (
189        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
190        $crate::thread_local!($($rest)*);
191    );
192
193    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => (
194        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
195    );
196
197    // process multiple declarations
198    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
199        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
200        $crate::thread_local!($($rest)*);
201    );
202
203    // handle a single declaration
204    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
205        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
206    );
207}
208
209/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
210#[stable(feature = "thread_local_try_with", since = "1.26.0")]
211#[non_exhaustive]
212#[derive(Clone, Copy, Eq, PartialEq)]
213pub struct AccessError;
214
215#[stable(feature = "thread_local_try_with", since = "1.26.0")]
216impl fmt::Debug for AccessError {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        f.debug_struct("AccessError").finish()
219    }
220}
221
222#[stable(feature = "thread_local_try_with", since = "1.26.0")]
223impl fmt::Display for AccessError {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        fmt::Display::fmt("already destroyed", f)
226    }
227}
228
229#[stable(feature = "thread_local_try_with", since = "1.26.0")]
230impl Error for AccessError {}
231
232// This ensures the panicking code is outlined from `with` for `LocalKey`.
233#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
234#[track_caller]
235#[cold]
236fn panic_access_error(err: AccessError) -> ! {
237    panic!("cannot access a Thread Local Storage value during or after destruction: {err:?}")
238}
239
240impl<T: 'static> LocalKey<T> {
241    #[doc(hidden)]
242    #[unstable(
243        feature = "thread_local_internals",
244        reason = "recently added to create a key",
245        issue = "none"
246    )]
247    pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> {
248        LocalKey { inner }
249    }
250
251    /// Acquires a reference to the value in this TLS key.
252    ///
253    /// This will lazily initialize the value if this thread has not referenced
254    /// this key yet.
255    ///
256    /// # Panics
257    ///
258    /// This function will `panic!()` if the key currently has its
259    /// destructor running, and it **may** panic if the destructor has
260    /// previously been run for this thread.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// thread_local! {
266    ///     pub static STATIC: String = String::from("I am");
267    /// }
268    ///
269    /// assert_eq!(
270    ///     STATIC.with(|original_value| format!("{original_value} initialized")),
271    ///     "I am initialized",
272    /// );
273    /// ```
274    #[stable(feature = "rust1", since = "1.0.0")]
275    pub fn with<F, R>(&'static self, f: F) -> R
276    where
277        F: FnOnce(&T) -> R,
278    {
279        match self.try_with(f) {
280            Ok(r) => r,
281            Err(err) => panic_access_error(err),
282        }
283    }
284
285    /// Acquires a reference to the value in this TLS key.
286    ///
287    /// This will lazily initialize the value if this thread has not referenced
288    /// this key yet. If the key has been destroyed (which may happen if this is called
289    /// in a destructor), this function will return an [`AccessError`].
290    ///
291    /// # Panics
292    ///
293    /// This function will still `panic!()` if the key is uninitialized and the
294    /// key's initializer panics.
295    ///
296    /// # Examples
297    ///
298    /// ```
299    /// thread_local! {
300    ///     pub static STATIC: String = String::from("I am");
301    /// }
302    ///
303    /// assert_eq!(
304    ///     STATIC.try_with(|original_value| format!("{original_value} initialized")),
305    ///     Ok(String::from("I am initialized")),
306    /// );
307    /// ```
308    #[stable(feature = "thread_local_try_with", since = "1.26.0")]
309    #[inline]
310    pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
311    where
312        F: FnOnce(&T) -> R,
313    {
314        let thread_local = unsafe { (self.inner)(None).as_ref().ok_or(AccessError)? };
315        Ok(f(thread_local))
316    }
317
318    /// Acquires a reference to the value in this TLS key, initializing it with
319    /// `init` if it wasn't already initialized on this thread.
320    ///
321    /// If `init` was used to initialize the thread local variable, `None` is
322    /// passed as the first argument to `f`. If it was already initialized,
323    /// `Some(init)` is passed to `f`.
324    ///
325    /// # Panics
326    ///
327    /// This function will panic if the key currently has its destructor
328    /// running, and it **may** panic if the destructor has previously been run
329    /// for this thread.
330    fn initialize_with<F, R>(&'static self, init: T, f: F) -> R
331    where
332        F: FnOnce(Option<T>, &T) -> R,
333    {
334        let mut init = Some(init);
335
336        let reference = unsafe {
337            match (self.inner)(Some(&mut init)).as_ref() {
338                Some(r) => r,
339                None => panic_access_error(AccessError),
340            }
341        };
342
343        f(init, reference)
344    }
345}
346
347impl<T: 'static> LocalKey<Cell<T>> {
348    /// Sets or initializes the contained value.
349    ///
350    /// Unlike the other methods, this will *not* run the lazy initializer of
351    /// the thread local. Instead, it will be directly initialized with the
352    /// given value if it wasn't initialized yet.
353    ///
354    /// # Panics
355    ///
356    /// Panics if the key currently has its destructor running,
357    /// and it **may** panic if the destructor has previously been run for this thread.
358    ///
359    /// # Examples
360    ///
361    /// ```
362    /// use std::cell::Cell;
363    ///
364    /// thread_local! {
365    ///     static X: Cell<i32> = panic!("!");
366    /// }
367    ///
368    /// // Calling X.get() here would result in a panic.
369    ///
370    /// X.set(123); // But X.set() is fine, as it skips the initializer above.
371    ///
372    /// assert_eq!(X.get(), 123);
373    /// ```
374    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
375    pub fn set(&'static self, value: T) {
376        self.initialize_with(Cell::new(value), |value, cell| {
377            if let Some(value) = value {
378                // The cell was already initialized, so `value` wasn't used to
379                // initialize it. So we overwrite the current value with the
380                // new one instead.
381                cell.set(value.into_inner());
382            }
383        });
384    }
385
386    /// Returns a copy of the contained value.
387    ///
388    /// This will lazily initialize the value if this thread has not referenced
389    /// this key yet.
390    ///
391    /// # Panics
392    ///
393    /// Panics if the key currently has its destructor running,
394    /// and it **may** panic if the destructor has previously been run for this thread.
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// use std::cell::Cell;
400    ///
401    /// thread_local! {
402    ///     static X: Cell<i32> = const { Cell::new(1) };
403    /// }
404    ///
405    /// assert_eq!(X.get(), 1);
406    /// ```
407    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
408    pub fn get(&'static self) -> T
409    where
410        T: Copy,
411    {
412        self.with(Cell::get)
413    }
414
415    /// Takes the contained value, leaving `Default::default()` in its place.
416    ///
417    /// This will lazily initialize the value if this thread has not referenced
418    /// this key yet.
419    ///
420    /// # Panics
421    ///
422    /// Panics if the key currently has its destructor running,
423    /// and it **may** panic if the destructor has previously been run for this thread.
424    ///
425    /// # Examples
426    ///
427    /// ```
428    /// use std::cell::Cell;
429    ///
430    /// thread_local! {
431    ///     static X: Cell<Option<i32>> = const { Cell::new(Some(1)) };
432    /// }
433    ///
434    /// assert_eq!(X.take(), Some(1));
435    /// assert_eq!(X.take(), None);
436    /// ```
437    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
438    pub fn take(&'static self) -> T
439    where
440        T: Default,
441    {
442        self.with(Cell::take)
443    }
444
445    /// Replaces the contained value, returning the old value.
446    ///
447    /// This will lazily initialize the value if this thread has not referenced
448    /// this key yet.
449    ///
450    /// # Panics
451    ///
452    /// Panics if the key currently has its destructor running,
453    /// and it **may** panic if the destructor has previously been run for this thread.
454    ///
455    /// # Examples
456    ///
457    /// ```
458    /// use std::cell::Cell;
459    ///
460    /// thread_local! {
461    ///     static X: Cell<i32> = const { Cell::new(1) };
462    /// }
463    ///
464    /// assert_eq!(X.replace(2), 1);
465    /// assert_eq!(X.replace(3), 2);
466    /// ```
467    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
468    #[rustc_confusables("swap")]
469    pub fn replace(&'static self, value: T) -> T {
470        self.with(|cell| cell.replace(value))
471    }
472}
473
474impl<T: 'static> LocalKey<RefCell<T>> {
475    /// Acquires a reference to the contained value.
476    ///
477    /// This will lazily initialize the value if this thread has not referenced
478    /// this key yet.
479    ///
480    /// # Panics
481    ///
482    /// Panics if the value is currently mutably borrowed.
483    ///
484    /// Panics if the key currently has its destructor running,
485    /// and it **may** panic if the destructor has previously been run for this thread.
486    ///
487    /// # Examples
488    ///
489    /// ```
490    /// use std::cell::RefCell;
491    ///
492    /// thread_local! {
493    ///     static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
494    /// }
495    ///
496    /// X.with_borrow(|v| assert!(v.is_empty()));
497    /// ```
498    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
499    pub fn with_borrow<F, R>(&'static self, f: F) -> R
500    where
501        F: FnOnce(&T) -> R,
502    {
503        self.with(|cell| f(&cell.borrow()))
504    }
505
506    /// Acquires a mutable reference to the contained value.
507    ///
508    /// This will lazily initialize the value if this thread has not referenced
509    /// this key yet.
510    ///
511    /// # Panics
512    ///
513    /// Panics if the value is currently borrowed.
514    ///
515    /// Panics if the key currently has its destructor running,
516    /// and it **may** panic if the destructor has previously been run for this thread.
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// use std::cell::RefCell;
522    ///
523    /// thread_local! {
524    ///     static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
525    /// }
526    ///
527    /// X.with_borrow_mut(|v| v.push(1));
528    ///
529    /// X.with_borrow(|v| assert_eq!(*v, vec![1]));
530    /// ```
531    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
532    pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R
533    where
534        F: FnOnce(&mut T) -> R,
535    {
536        self.with(|cell| f(&mut cell.borrow_mut()))
537    }
538
539    /// Sets or initializes the contained value.
540    ///
541    /// Unlike the other methods, this will *not* run the lazy initializer of
542    /// the thread local. Instead, it will be directly initialized with the
543    /// given value if it wasn't initialized yet.
544    ///
545    /// # Panics
546    ///
547    /// Panics if the value is currently borrowed.
548    ///
549    /// Panics if the key currently has its destructor running,
550    /// and it **may** panic if the destructor has previously been run for this thread.
551    ///
552    /// # Examples
553    ///
554    /// ```
555    /// use std::cell::RefCell;
556    ///
557    /// thread_local! {
558    ///     static X: RefCell<Vec<i32>> = panic!("!");
559    /// }
560    ///
561    /// // Calling X.with() here would result in a panic.
562    ///
563    /// X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above.
564    ///
565    /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
566    /// ```
567    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
568    pub fn set(&'static self, value: T) {
569        self.initialize_with(RefCell::new(value), |value, cell| {
570            if let Some(value) = value {
571                // The cell was already initialized, so `value` wasn't used to
572                // initialize it. So we overwrite the current value with the
573                // new one instead.
574                *cell.borrow_mut() = value.into_inner();
575            }
576        });
577    }
578
579    /// Takes the contained value, leaving `Default::default()` in its place.
580    ///
581    /// This will lazily initialize the value if this thread has not referenced
582    /// this key yet.
583    ///
584    /// # Panics
585    ///
586    /// Panics if the value is currently borrowed.
587    ///
588    /// Panics if the key currently has its destructor running,
589    /// and it **may** panic if the destructor has previously been run for this thread.
590    ///
591    /// # Examples
592    ///
593    /// ```
594    /// use std::cell::RefCell;
595    ///
596    /// thread_local! {
597    ///     static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
598    /// }
599    ///
600    /// X.with_borrow_mut(|v| v.push(1));
601    ///
602    /// let a = X.take();
603    ///
604    /// assert_eq!(a, vec![1]);
605    ///
606    /// X.with_borrow(|v| assert!(v.is_empty()));
607    /// ```
608    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
609    pub fn take(&'static self) -> T
610    where
611        T: Default,
612    {
613        self.with(RefCell::take)
614    }
615
616    /// Replaces the contained value, returning the old value.
617    ///
618    /// # Panics
619    ///
620    /// Panics if the value is currently borrowed.
621    ///
622    /// Panics if the key currently has its destructor running,
623    /// and it **may** panic if the destructor has previously been run for this thread.
624    ///
625    /// # Examples
626    ///
627    /// ```
628    /// use std::cell::RefCell;
629    ///
630    /// thread_local! {
631    ///     static X: RefCell<Vec<i32>> = RefCell::new(Vec::new());
632    /// }
633    ///
634    /// let prev = X.replace(vec![1, 2, 3]);
635    /// assert!(prev.is_empty());
636    ///
637    /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3]));
638    /// ```
639    #[stable(feature = "local_key_cell_methods", since = "1.73.0")]
640    #[rustc_confusables("swap")]
641    pub fn replace(&'static self, value: T) -> T {
642        self.with(|cell| cell.replace(value))
643    }
644}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy