summaryrefslogtreecommitdiffstats
path: root/library/std/src/thread
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/thread')
-rw-r--r--library/std/src/thread/local.rs34
-rw-r--r--library/std/src/thread/mod.rs35
-rw-r--r--library/std/src/thread/tests.rs4
3 files changed, 48 insertions, 25 deletions
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 7fdf03acc..1b86d898c 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -18,8 +18,8 @@ use crate::fmt;
/// target platform. It is instantiated with the [`thread_local!`] macro and the
/// primary method is the [`with`] method.
///
-/// The [`with`] method yields a reference to the contained value which cannot be
-/// sent across threads or escape the given closure.
+/// The [`with`] method yields a reference to the contained value which cannot
+/// outlive the current thread or escape the given closure.
///
/// [`thread_local!`]: crate::thread_local
///
@@ -134,10 +134,28 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
/// thread_local! {
/// pub static FOO: RefCell<u32> = RefCell::new(1);
///
-/// #[allow(unused)]
/// static BAR: RefCell<f32> = RefCell::new(1.0);
/// }
-/// # fn main() {}
+///
+/// FOO.with(|foo| assert_eq!(*foo.borrow(), 1));
+/// BAR.with(|bar| assert_eq!(*bar.borrow(), 1.0));
+/// ```
+///
+/// This macro supports a special `const {}` syntax that can be used
+/// when the initialization expression can be evaluated as a constant.
+/// This can enable a more efficient thread local implementation that
+/// can avoid lazy initialization. For types that do not
+/// [need to be dropped][crate::mem::needs_drop], this can enable an
+/// even more efficient implementation that does not need to
+/// track any additional state.
+///
+/// ```
+/// use std::cell::Cell;
+/// thread_local! {
+/// pub static FOO: Cell<u32> = const { Cell::new(1) };
+/// }
+///
+/// FOO.with(|foo| assert_eq!(foo.get(), 1));
/// ```
///
/// See [`LocalKey` documentation][`std::thread::LocalKey`] for more
@@ -153,23 +171,23 @@ macro_rules! thread_local {
() => {};
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
- $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
+ $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
$crate::thread_local!($($rest)*);
);
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
- $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
+ $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
);
// process multiple declarations
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
- $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
$crate::thread_local!($($rest)*);
);
// handle a single declaration
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
- $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
);
}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 13b845b25..f712c8727 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -193,20 +193,23 @@ pub use scoped::{scope, Scope, ScopedJoinHandle};
#[macro_use]
mod local;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::local::{AccessError, LocalKey};
-
-// Provide the type used by the thread_local! macro to access TLS keys. This
-// needs to be kept in sync with the macro itself (in `local.rs`).
-// There are three types: "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 elf linker. "static" is for single-threaded platforms where a global
-// static is sufficient.
-
-#[doc(hidden)]
-#[unstable(feature = "libstd_thread_internals", issue = "none")]
-pub use crate::sys::common::thread_local::Key as __LocalKeyInner;
+cfg_if::cfg_if! {
+ if #[cfg(test)] {
+ // Avoid duplicating the global state assoicated with thread-locals between this crate and
+ // realstd. Miri relies on this.
+ pub use realstd::thread::{local_impl, AccessError, LocalKey};
+ } else {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use self::local::{AccessError, LocalKey};
+
+ // Implementation details used by the thread_local!{} macro.
+ #[doc(hidden)]
+ #[unstable(feature = "thread_local_internals", issue = "none")]
+ pub mod local_impl {
+ pub use crate::sys::common::thread_local::{thread_local_inner, Key};
+ }
+ }
+}
////////////////////////////////////////////////////////////////////////////////
// Builder
@@ -494,7 +497,7 @@ impl Builder {
MaybeDangling(mem::MaybeUninit::new(x))
}
fn into_inner(self) -> T {
- // SAFETY: we are always initiailized.
+ // SAFETY: we are always initialized.
let ret = unsafe { self.0.assume_init_read() };
// Make sure we don't drop.
mem::forget(self);
@@ -503,7 +506,7 @@ impl Builder {
}
impl<T> Drop for MaybeDangling<T> {
fn drop(&mut self) {
- // SAFETY: we are always initiailized.
+ // SAFETY: we are always initialized.
unsafe { self.0.assume_init_drop() };
}
}
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index 6c9ce6fa0..b65e2572c 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -375,7 +375,9 @@ fn test_scoped_threads_nll() {
// this is mostly a *compilation test* for this exact function:
fn foo(x: &u8) {
thread::scope(|s| {
- s.spawn(|| drop(x));
+ s.spawn(|| match x {
+ _ => (),
+ });
});
}
// let's also run it for good measure