diff options
Diffstat (limited to 'library/std/src/sys/thread_local/static_local.rs')
| -rw-r--r-- | library/std/src/sys/thread_local/static_local.rs | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/library/std/src/sys/thread_local/static_local.rs b/library/std/src/sys/thread_local/static_local.rs new file mode 100644 index 00000000000..4f2b6868962 --- /dev/null +++ b/library/std/src/sys/thread_local/static_local.rs @@ -0,0 +1,108 @@ +use super::lazy::LazyKeyInner; +use crate::fmt; + +#[doc(hidden)] +#[allow_internal_unstable(thread_local_internals)] +#[allow_internal_unsafe] +#[unstable(feature = "thread_local_internals", issue = "none")] +#[rustc_macro_transparency = "semitransparent"] +pub macro thread_local_inner { + // used to generate the `LocalKey` value for const-initialized thread locals + (@key $t:ty, const $init:expr) => {{ + #[inline] // see comments below + #[deny(unsafe_op_in_unsafe_fn)] + // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint + #[cfg_attr(bootstrap, allow(static_mut_ref))] + #[cfg_attr(not(bootstrap), allow(static_mut_refs))] + unsafe fn __getit( + _init: $crate::option::Option<&mut $crate::option::Option<$t>>, + ) -> $crate::option::Option<&'static $t> { + const INIT_EXPR: $t = $init; + + // wasm without atomics maps directly to `static mut`, and dtors + // aren't implemented because thread dtors aren't really a thing + // on wasm right now + // + // FIXME(#84224) this should come after the `target_thread_local` + // block. + static mut VAL: $t = INIT_EXPR; + unsafe { $crate::option::Option::Some(&VAL) } + } + + unsafe { + $crate::thread::LocalKey::new(__getit) + } + }}, + + // used to generate the `LocalKey` value for `thread_local!` + (@key $t:ty, $init:expr) => { + { + #[inline] + fn __init() -> $t { $init } + #[inline] + unsafe fn __getit( + init: $crate::option::Option<&mut $crate::option::Option<$t>>, + ) -> $crate::option::Option<&'static $t> { + static __KEY: $crate::thread::local_impl::Key<$t> = + $crate::thread::local_impl::Key::new(); + + unsafe { + __KEY.get(move || { + if let $crate::option::Option::Some(init) = init { + if let $crate::option::Option::Some(value) = init.take() { + return value; + } else if $crate::cfg!(debug_assertions) { + $crate::unreachable!("missing default value"); + } + } + __init() + }) + } + } + + unsafe { + $crate::thread::LocalKey::new(__getit) + } + } + }, + ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { + $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = + $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); + }, +} + +/// On some targets like wasm there's no threads, so no need to generate +/// thread locals and we can instead just use plain statics! + +pub struct Key<T> { + inner: LazyKeyInner<T>, +} + +unsafe impl<T> Sync for Key<T> {} + +impl<T> fmt::Debug for Key<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Key").finish_non_exhaustive() + } +} + +impl<T> Key<T> { + pub const fn new() -> Key<T> { + Key { inner: LazyKeyInner::new() } + } + + pub unsafe fn get(&self, init: impl FnOnce() -> T) -> 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. + let value = unsafe { + match self.inner.get() { + Some(ref value) => value, + None => self.inner.initialize(init), + } + }; + + Some(value) + } +} |
