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