1 | #![unstable (feature = "thread_local_internals" , reason = "should not be necessary" , issue = "none" )] |
2 | |
3 | // There are three thread-local implementations: "static", "fast", "OS". |
4 | // The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the |
5 | // "fast" key type is accessed via code generated via LLVM, where TLS keys are set up by the linker. |
6 | // "static" is for single-threaded platforms where a global static is sufficient. |
7 | |
8 | cfg_if::cfg_if! { |
9 | if #[cfg(any(all(target_family = "wasm" , not(target_feature = "atomics" )), target_os = "uefi" ))] { |
10 | #[doc (hidden)] |
11 | mod static_local; |
12 | #[doc (hidden)] |
13 | pub use static_local::{Key, thread_local_inner}; |
14 | } else if #[cfg(target_thread_local)] { |
15 | #[doc (hidden)] |
16 | mod fast_local; |
17 | #[doc (hidden)] |
18 | pub use fast_local::{Key, thread_local_inner}; |
19 | } else { |
20 | #[doc (hidden)] |
21 | mod os_local; |
22 | #[doc (hidden)] |
23 | pub use os_local::{Key, thread_local_inner}; |
24 | } |
25 | } |
26 | |
27 | mod lazy { |
28 | use crate::cell::UnsafeCell; |
29 | use crate::hint; |
30 | use crate::mem; |
31 | |
32 | pub struct LazyKeyInner<T> { |
33 | inner: UnsafeCell<Option<T>>, |
34 | } |
35 | |
36 | impl<T> LazyKeyInner<T> { |
37 | pub const fn new() -> LazyKeyInner<T> { |
38 | LazyKeyInner { inner: UnsafeCell::new(None) } |
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 = 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 | |