about summary refs log tree commit diff
path: root/library/std/src/sys/thread_local/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/thread_local/mod.rs')
-rw-r--r--library/std/src/sys/thread_local/mod.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
new file mode 100644
index 00000000000..8b2c839f837
--- /dev/null
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -0,0 +1,124 @@
+#![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
+
+// There are three thread-local implementations: "static", "fast", "OS".
+// The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the
+// "fast" key type is accessed via code generated via LLVM, where TLS keys are set up by the linker.
+// "static" is for single-threaded platforms where a global static is sufficient.
+
+cfg_if::cfg_if! {
+    if #[cfg(any(all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi"))] {
+        #[doc(hidden)]
+        mod static_local;
+        #[doc(hidden)]
+        pub use static_local::{Key, thread_local_inner};
+    } else if #[cfg(target_thread_local)] {
+        #[doc(hidden)]
+        mod fast_local;
+        #[doc(hidden)]
+        pub use fast_local::{Key, thread_local_inner};
+    } else {
+        #[doc(hidden)]
+        mod os_local;
+        #[doc(hidden)]
+        pub use os_local::{Key, thread_local_inner};
+    }
+}
+
+mod lazy {
+    use crate::cell::UnsafeCell;
+    use crate::hint;
+    use crate::mem;
+
+    pub struct LazyKeyInner<T> {
+        inner: UnsafeCell<Option<T>>,
+    }
+
+    impl<T> LazyKeyInner<T> {
+        pub const fn new() -> LazyKeyInner<T> {
+            LazyKeyInner { inner: UnsafeCell::new(None) }
+        }
+
+        pub unsafe fn get(&self) -> Option<&'static T> {
+            // SAFETY: The caller must ensure no reference is ever handed out to
+            // the inner cell nor mutable reference to the Option<T> inside said
+            // cell. This make it safe to hand a reference, though the lifetime
+            // of 'static is itself unsafe, making the get method unsafe.
+            unsafe { (*self.inner.get()).as_ref() }
+        }
+
+        /// The caller must ensure that no reference is active: this method
+        /// needs unique access.
+        pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
+            // Execute the initialization up front, *then* move it into our slot,
+            // just in case initialization fails.
+            let value = init();
+            let ptr = self.inner.get();
+
+            // SAFETY:
+            //
+            // note that this can in theory just be `*ptr = Some(value)`, but due to
+            // the compiler will currently codegen that pattern with something like:
+            //
+            //      ptr::drop_in_place(ptr)
+            //      ptr::write(ptr, Some(value))
+            //
+            // Due to this pattern it's possible for the destructor of the value in
+            // `ptr` (e.g., if this is being recursively initialized) to re-access
+            // TLS, in which case there will be a `&` and `&mut` pointer to the same
+            // value (an aliasing violation). To avoid setting the "I'm running a
+            // destructor" flag we just use `mem::replace` which should sequence the
+            // operations a little differently and make this safe to call.
+            //
+            // The precondition also ensures that we are the only one accessing
+            // `self` at the moment so replacing is fine.
+            unsafe {
+                let _ = mem::replace(&mut *ptr, Some(value));
+            }
+
+            // SAFETY: With the call to `mem::replace` it is guaranteed there is
+            // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked`
+            // will never be reached.
+            unsafe {
+                // After storing `Some` we want to get a reference to the contents of
+                // what we just stored. While we could use `unwrap` here and it should
+                // always work it empirically doesn't seem to always get optimized away,
+                // which means that using something like `try_with` can pull in
+                // panicking code and cause a large size bloat.
+                match *ptr {
+                    Some(ref x) => x,
+                    None => hint::unreachable_unchecked(),
+                }
+            }
+        }
+
+        /// The other methods hand out references while taking &self.
+        /// As such, callers of this method must ensure no `&` and `&mut` are
+        /// available and used at the same time.
+        #[allow(unused)]
+        pub unsafe fn take(&mut self) -> Option<T> {
+            // SAFETY: See doc comment for this method.
+            unsafe { (*self.inner.get()).take() }
+        }
+    }
+}
+
+/// Run a callback in a scenario which must not unwind (such as a `extern "C"
+/// fn` declared in a user crate). If the callback unwinds anyway, then
+/// `rtabort` with a message about thread local panicking on drop.
+#[inline]
+pub fn abort_on_dtor_unwind(f: impl FnOnce()) {
+    // Using a guard like this is lower cost.
+    let guard = DtorUnwindGuard;
+    f();
+    core::mem::forget(guard);
+
+    struct DtorUnwindGuard;
+    impl Drop for DtorUnwindGuard {
+        #[inline]
+        fn drop(&mut self) {
+            // This is not terribly descriptive, but it doesn't need to be as we'll
+            // already have printed a panic message at this point.
+            rtabort!("thread local panicked on drop");
+        }
+    }
+}