Add more from the std
This commit is contained in:
150
crates/std/src/sys/thread_local/no_threads.rs
Normal file
150
crates/std/src/sys/thread_local/no_threads.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
//! On some targets like wasm there's no threads, so no need to generate
|
||||
//! thread locals and we can instead just use plain statics!
|
||||
|
||||
use crate::cell::{Cell, UnsafeCell};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow_internal_unstable(thread_local_internals)]
|
||||
#[allow_internal_unsafe]
|
||||
#[unstable(feature = "thread_local_internals", issue = "none")]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro thread_local_inner {
|
||||
// used to generate the `LocalKey` value for const-initialized thread locals
|
||||
(@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
|
||||
const __RUST_STD_INTERNAL_INIT: $t = $init;
|
||||
|
||||
// NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
|
||||
unsafe {
|
||||
$crate::thread::LocalKey::new(|_| {
|
||||
$(#[$align_attr])*
|
||||
static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::EagerStorage<$t> =
|
||||
$crate::thread::local_impl::EagerStorage { value: __RUST_STD_INTERNAL_INIT };
|
||||
&__RUST_STD_INTERNAL_VAL.value
|
||||
})
|
||||
}
|
||||
}},
|
||||
|
||||
// used to generate the `LocalKey` value for `thread_local!`
|
||||
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
|
||||
#[inline]
|
||||
fn __rust_std_internal_init_fn() -> $t { $init }
|
||||
|
||||
unsafe {
|
||||
$crate::thread::LocalKey::new(|__rust_std_internal_init| {
|
||||
$(#[$align_attr])*
|
||||
static __RUST_STD_INTERNAL_VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
|
||||
__RUST_STD_INTERNAL_VAL.get(__rust_std_internal_init, __rust_std_internal_init_fn)
|
||||
})
|
||||
}
|
||||
}},
|
||||
}
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
|
||||
pub struct EagerStorage<T> {
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
// SAFETY: the target doesn't have threads.
|
||||
unsafe impl<T> Sync for EagerStorage<T> {}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum State {
|
||||
Initial,
|
||||
Alive,
|
||||
Destroying,
|
||||
}
|
||||
|
||||
#[allow(missing_debug_implementations)]
|
||||
#[repr(C)]
|
||||
pub struct LazyStorage<T> {
|
||||
// This field must be first, for correctness of `#[rustc_align_static]`
|
||||
value: UnsafeCell<MaybeUninit<T>>,
|
||||
state: Cell<State>,
|
||||
}
|
||||
|
||||
impl<T> LazyStorage<T> {
|
||||
pub const fn new() -> LazyStorage<T> {
|
||||
LazyStorage {
|
||||
value: UnsafeCell::new(MaybeUninit::uninit()),
|
||||
state: Cell::new(State::Initial),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a pointer to the TLS value, potentially initializing it with the
|
||||
/// provided parameters.
|
||||
///
|
||||
/// The resulting pointer may not be used after reentrant inialialization
|
||||
/// has occurred.
|
||||
#[inline]
|
||||
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
|
||||
if self.state.get() == State::Alive {
|
||||
self.value.get() as *const T
|
||||
} else {
|
||||
self.initialize(i, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cold]
|
||||
fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
|
||||
let value = i.and_then(Option::take).unwrap_or_else(f);
|
||||
|
||||
// Destroy the old value if it is initialized
|
||||
// FIXME(#110897): maybe panic on recursive initialization.
|
||||
if self.state.get() == State::Alive {
|
||||
self.state.set(State::Destroying);
|
||||
// Safety: we check for no initialization during drop below
|
||||
unsafe {
|
||||
ptr::drop_in_place(self.value.get() as *mut T);
|
||||
}
|
||||
self.state.set(State::Initial);
|
||||
}
|
||||
|
||||
// Guard against initialization during drop
|
||||
if self.state.get() == State::Destroying {
|
||||
panic!("Attempted to initialize thread-local while it is being dropped");
|
||||
}
|
||||
|
||||
unsafe {
|
||||
self.value.get().write(MaybeUninit::new(value));
|
||||
}
|
||||
self.state.set(State::Alive);
|
||||
|
||||
self.value.get() as *const T
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: the target doesn't have threads.
|
||||
unsafe impl<T> Sync for LazyStorage<T> {}
|
||||
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub(crate) macro local_pointer {
|
||||
() => {},
|
||||
($vis:vis static $name:ident; $($rest:tt)*) => {
|
||||
$vis static $name: $crate::sys::thread_local::LocalPointer = $crate::sys::thread_local::LocalPointer::__new();
|
||||
$crate::sys::thread_local::local_pointer! { $($rest)* }
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct LocalPointer {
|
||||
p: Cell<*mut ()>,
|
||||
}
|
||||
|
||||
impl LocalPointer {
|
||||
pub const fn __new() -> LocalPointer {
|
||||
LocalPointer { p: Cell::new(ptr::null_mut()) }
|
||||
}
|
||||
|
||||
pub fn get(&self) -> *mut () {
|
||||
self.p.get()
|
||||
}
|
||||
|
||||
pub fn set(&self, p: *mut ()) {
|
||||
self.p.set(p)
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: the target doesn't have threads.
|
||||
unsafe impl Sync for LocalPointer {}
|
||||
Reference in New Issue
Block a user