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
8cfg_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
27mod 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]
109pub 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