std\sys\thread_local/
os.rs

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