1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")]
// 共有三种线程本地实现: "static"、"fast"、"OS"。
// "OS" 线程本地密钥类型通过特定于平台的 API 调用访问并且速度很慢,而 "fast" 密钥类型通过 LLVM 生成的代码访问,其中 TLS 密钥由链接器设置。
//
// "static" 是一个单一静态线程就足够的平台。
cfg_if::cfg_if! {
if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
#[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: 调用者必须确保绝不向内部 cell 传递任何引用,也不要向所述 cell 内部的 Option<T> 进行可变引用。
// 尽管'static 的生命周期本身是不安全的,这使 get 方法变得不安全,但这使引用变得安全。
//
//
unsafe { (*self.inner.get()).as_ref() }
}
/// 调用者必须确保没有激活引用:此方法需要唯一的访问权限。
///
pub unsafe fn initialize<F: FnOnce() -> T>(&self, init: F) -> &'static T {
// 预先执行初始化,然后将其移动到我们的插槽中,以防万一初始化失败。
//
let value = init();
let ptr = self.inner.get();
// SAFETY:
//
// 请注意,从理论上讲,它只能是 `*ptr = Some(value)`,但是由于编译器当前将使用类似以下内容的代码生成该模式:
//
// ptr::drop_in_place(ptr)
// ptr::write(ptr, Some(value))
//
// 由于这种模式,`ptr` 中的值的析构函数有可能重新访问 TLS (例如,如果正在递归初始化),在这种情况下,将有一个指向相同值的 `&` 和 `&mut` 指针 (违反别名)。
// 为了避免设置 "我正在运行析构函数" 标志,我们只使用 `mem::replace`,它应该以稍微不同的方式对操作进行排序,并确保调用安全。
//
// 前提条件还确保了我们是目前唯一访问 `self` 的计算机,因此可以很好地进行替换。
//
//
//
//
//
//
unsafe {
let _ = mem::replace(&mut *ptr, Some(value));
}
// SAFETY: 通过调用 `mem::replace`,可以确保 `ptr` 后面有一个 `Some`,而不是 `None`,因此将永远无法到达 `unreachable_unchecked`。
//
//
unsafe {
// 存储 `Some` 之后,我们想对刚刚存储的内容进行引用。
// 尽管我们可以在这里使用 `unwrap`,并且它应该始终有效,但是根据经验,似乎并没有总是对其进行优化,这意味着使用 `try_with` 之类的东西可能会引入 panic 代码并导致大规模的膨胀。
//
//
//
match *ptr {
Some(ref x) => x,
None => hint::unreachable_unchecked(),
}
}
}
/// 其他方法在取 &self 时分发引用。
/// 因此,此方法的调用者必须确保没有 `&` 和 `&mut` 同时可用和使用。
///
#[allow(unused)]
pub unsafe fn take(&mut self) -> Option<T> {
// SAFETY: 有关此方法,请参见文档注释。
unsafe { (*self.inner.get()).take() }
}
}
}