xref: /drstd/src/std/sys/common/thread_local/mod.rs (revision 86982c5e9b2eaa583327251616ee822c36288824)
1 // There are three thread-local implementations: "static", "fast", "OS".
2 // The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the
3 // "fast" key type is accessed via code generated via LLVM, where TLS keys are set up by the linker.
4 // "static" is for single-threaded platforms where a global static is sufficient.
5 
6 cfg_if::cfg_if! {
7     if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
8         #[doc(hidden)]
9         mod static_local;
10         #[doc(hidden)]
11         pub use static_local::{Key, thread_local_inner};
12     } else if #[cfg(target_thread_local)] {
13         #[doc(hidden)]
14         mod fast_local;
15         #[doc(hidden)]
16         pub use fast_local::{Key, thread_local_inner};
17     } else {
18         #[doc(hidden)]
19         mod os_local;
20         #[doc(hidden)]
21         pub use os_local::{Key, thread_local_inner};
22     }
23 }
24 
25 mod lazy {
26     use crate::std::cell::UnsafeCell;
27     use crate::std::hint;
28     use crate::std::mem;
29 
30     pub struct LazyKeyInner<T> {
31         inner: UnsafeCell<Option<T>>,
32     }
33 
34     impl<T> LazyKeyInner<T> {
35         pub const fn new() -> LazyKeyInner<T> {
36             LazyKeyInner {
37                 inner: UnsafeCell::new(None),
38             }
39         }
40 
41         pub unsafe fn get(&self) -> Option<&'static T> {
42             // SAFETY: The caller must ensure no reference is ever handed out to
43             // the inner cell nor mutable reference to the Option<T> inside said
44             // cell. This make it safe to hand a reference, though the lifetime
45             // of 'static is itself unsafe, making the get method unsafe.
46             unsafe { (*self.inner.get()).as_ref() }
47         }
48 
49         /// The caller must ensure that no reference is active: this method
50         /// needs unique access.
51         pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
52             // Execute the initialization up front, *then* move it into our slot,
53             // just in case initialization fails.
54             let value = init();
55             let ptr = self.inner.get();
56 
57             // SAFETY:
58             //
59             // note that this can in theory just be `*ptr = Some(value)`, but due to
60             // the compiler will currently codegen that pattern with something like:
61             //
62             //      ptr::drop_in_place(ptr)
63             //      ptr::write(ptr, Some(value))
64             //
65             // Due to this pattern it's possible for the destructor of the value in
66             // `ptr` (e.g., if this is being recursively initialized) to re-access
67             // TLS, in which case there will be a `&` and `&mut` pointer to the same
68             // value (an aliasing violation). To avoid setting the "I'm running a
69             // destructor" flag we just use `mem::replace` which should sequence the
70             // operations a little differently and make this safe to call.
71             //
72             // The precondition also ensures that we are the only one accessing
73             // `self` at the moment so replacing is fine.
74             unsafe {
75                 let _ = mem::replace(&mut *ptr, Some(value));
76             }
77 
78             // SAFETY: With the call to `mem::replace` it is guaranteed there is
79             // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
80             // will never be reached.
81             unsafe {
82                 // After storing `Some` we want to get a reference to the contents of
83                 // what we just stored. While we could use `unwrap` here and it should
84                 // always work it empirically doesn't seem to always get optimized away,
85                 // which means that using something like `try_with` can pull in
86                 // panicking code and cause a large size bloat.
87                 match *ptr {
88                     Some(ref x) => x,
89                     None => hint::unreachable_unchecked(),
90                 }
91             }
92         }
93 
94         /// The other methods hand out references while taking &self.
95         /// As such, callers of this method must ensure no `&` and `&mut` are
96         /// available and used at the same time.
97         #[allow(unused)]
98         pub unsafe fn take(&mut self) -> Option<T> {
99             // SAFETY: See doc comment for this method.
100             unsafe { (*self.inner.get()).take() }
101         }
102     }
103 }
104 
105 /// Run a callback in a scenario which must not unwind (such as a `extern "C"
106 /// fn` declared in a user crate). If the callback unwinds anyway, then
107 /// `rtabort` with a message about thread local panicking on drop.
108 #[inline]
109 pub fn abort_on_dtor_unwind(f: impl FnOnce()) {
110     // Using a guard like this is lower cost.
111     let guard = DtorUnwindGuard;
112     f();
113     core::mem::forget(guard);
114 
115     struct DtorUnwindGuard;
116     impl Drop for DtorUnwindGuard {
117         #[inline]
118         fn drop(&mut self) {
119             // This is not terribly descriptive, but it doesn't need to be as we'll
120             // already have printed a panic message at this point.
121             rtabort!("thread local panicked on drop");
122         }
123     }
124 }
125