提交 6bd3ab0d 编写于 作者: A Aaron Turon

Implement RFC 909: move thread_local into thread

This commit implements [RFC
909](https://github.com/rust-lang/rfcs/pull/909):

The `std::thread_local` module is now deprecated, and its contents are
available directly in `std::thread` as `LocalKey`, `LocalKeyState`, and
`ScopedKey`.

The macros remain exactly as they were, which means little if any code
should break. Nevertheless, this is technically a:

[breaking-change]

Closes #23547
上级 b0aad7dd
......@@ -249,30 +249,23 @@
/* Runtime and platform support */
#[macro_use]
pub mod thread_local;
pub mod thread;
pub mod collections;
pub mod dynamic_lib;
pub mod env;
pub mod ffi;
pub mod old_io;
pub mod io;
pub mod fs;
pub mod io;
pub mod net;
pub mod old_io;
pub mod old_path;
pub mod os;
pub mod env;
pub mod path;
pub mod old_path;
pub mod process;
pub mod rand;
pub mod time;
/* Common data structures */
pub mod collections;
/* Threads and communication */
pub mod thread;
pub mod sync;
pub mod time;
#[macro_use]
#[path = "sys/common/mod.rs"] mod sys_common;
......@@ -305,7 +298,7 @@ mod std {
pub use rt; // used for panic!()
pub use vec; // used for vec![]
pub use cell; // used for tls!
pub use thread_local; // used for thread_local!
pub use thread; // used for thread_local!
pub use marker; // used for tls!
pub use ops; // used for bitflags!
......
......@@ -15,7 +15,7 @@
use cell::RefCell;
use string::String;
use thread::Thread;
use thread_local::State;
use thread::LocalKeyState;
struct ThreadInfo {
stack_guard: uint,
......@@ -26,7 +26,7 @@ struct ThreadInfo {
impl ThreadInfo {
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
if THREAD_INFO.state() == State::Destroyed {
if THREAD_INFO.state() == LocalKeyState::Destroyed {
panic!("Use of std::thread::current() is not possible after \
the thread's local data has been destroyed");
}
......
......@@ -9,40 +9,13 @@
// except according to those terms.
//! Thread local storage
//!
//! This module provides an implementation of thread local storage for Rust
//! programs. Thread local storage is a method of storing data into a global
//! variable which each thread in the program will have its own copy of.
//! Threads do not share this data, so accesses do not need to be synchronized.
//!
//! At a high level, this module provides two variants of storage:
//!
//! * Owning thread local storage. This is a type of thread local key which
//! owns the value that it contains, and will destroy the value when the
//! thread exits. This variant is created with the `thread_local!` macro and
//! can contain any value which is `'static` (no borrowed pointers.
//!
//! * Scoped thread local storage. This type of key is used to store a reference
//! to a value into local storage temporarily for the scope of a function
//! call. There are no restrictions on what types of values can be placed
//! into this key.
//!
//! Both forms of thread local storage provide an accessor function, `with`,
//! which will yield a shared reference to the value to the specified
//! closure. Thread local keys only allow shared access to values as there is no
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
//! will want to make use of some form of **interior mutability** through the
//! `Cell` or `RefCell` types.
#![stable(feature = "rust1", since = "1.0.0")]
#![unstable(feature = "thread_local_internals")]
use prelude::v1::*;
use cell::UnsafeCell;
#[macro_use]
pub mod scoped;
// Sure wish we had macro hygiene, no?
#[doc(hidden)]
#[unstable(feature = "thread_local_internals")]
......@@ -95,7 +68,7 @@ pub mod __impl {
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Key<T> {
pub struct LocalKey<T> {
// The key itself may be tagged with #[thread_local], and this `Key` is
// stored as a `static`, and it's not valid for a static to reference the
// address of another thread_local static. For this reason we kinda wonkily
......@@ -114,15 +87,15 @@ pub struct Key<T> {
pub init: fn() -> T,
}
/// Declare a new thread local storage key of type `std::thread_local::Key`.
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
macro_rules! thread_local {
(static $name:ident: $t:ty = $init:expr) => (
static $name: ::std::thread_local::Key<$t> = {
static $name: ::std::thread::LocalKey<$t> = {
use std::cell::UnsafeCell as __UnsafeCell;
use std::thread_local::__impl::KeyInner as __KeyInner;
use std::thread::__local::__impl::KeyInner as __KeyInner;
use std::option::Option as __Option;
use std::option::Option::None as __None;
......@@ -133,13 +106,13 @@ fn __init() -> $t { $init }
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
&__KEY
}
::std::thread_local::Key { inner: __getit, init: __init }
::std::thread::LocalKey { inner: __getit, init: __init }
};
);
(pub static $name:ident: $t:ty = $init:expr) => (
pub static $name: ::std::thread_local::Key<$t> = {
pub static $name: ::std::thread::LocalKey<$t> = {
use std::cell::UnsafeCell as __UnsafeCell;
use std::thread_local::__impl::KeyInner as __KeyInner;
use std::thread::__local::__impl::KeyInner as __KeyInner;
use std::option::Option as __Option;
use std::option::Option::None as __None;
......@@ -150,7 +123,7 @@ fn __init() -> $t { $init }
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
&__KEY
}
::std::thread_local::Key { inner: __getit, init: __init }
::std::thread::LocalKey { inner: __getit, init: __init }
};
);
}
......@@ -183,20 +156,20 @@ fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
not(target_arch = "aarch64")),
thread_local)]
static $name: ::std::thread_local::__impl::KeyInner<$t> =
static $name: ::std::thread::__local::__impl::KeyInner<$t> =
__thread_local_inner!($init, $t);
);
(pub static $name:ident: $t:ty = $init:expr) => (
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
not(target_arch = "aarch64")),
thread_local)]
pub static $name: ::std::thread_local::__impl::KeyInner<$t> =
pub static $name: ::std::thread::__local::__impl::KeyInner<$t> =
__thread_local_inner!($init, $t);
);
($init:expr, $t:ty) => ({
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
::std::thread_local::__impl::KeyInner {
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
::std::thread::__local::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: $init },
dtor_registered: ::std::cell::UnsafeCell { value: false },
dtor_running: ::std::cell::UnsafeCell { value: false },
......@@ -204,15 +177,15 @@ fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
};
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
unsafe extern fn __destroy(ptr: *mut u8) {
::std::thread_local::__impl::destroy_value::<$t>(ptr);
::std::thread::__local::__impl::destroy_value::<$t>(ptr);
}
::std::thread_local::__impl::KeyInner {
::std::thread::__local::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: $init },
os: ::std::thread_local::__impl::OsStaticKey {
inner: ::std::thread_local::__impl::OS_INIT_INNER,
os: ::std::thread::__local::__impl::OsStaticKey {
inner: ::std::thread::__local::__impl::OS_INIT_INNER,
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
},
}
......@@ -226,7 +199,7 @@ fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
#[unstable(feature = "std_misc",
reason = "state querying was recently added")]
#[derive(Eq, PartialEq, Copy)]
pub enum State {
pub enum LocalKeyState {
/// All keys are in this state whenever a thread starts. Keys will
/// transition to the `Valid` state once the first call to `with` happens
/// and the initialization expression succeeds.
......@@ -253,7 +226,7 @@ pub enum State {
Destroyed,
}
impl<T: 'static> Key<T> {
impl<T: 'static> LocalKey<T> {
/// Acquire a reference to the value in this TLS key.
///
/// This will lazily initialize the value if this thread has not referenced
......@@ -309,16 +282,16 @@ unsafe fn init(&self, slot: &UnsafeCell<Option<T>>) -> &T {
/// any call to `with`.
#[unstable(feature = "std_misc",
reason = "state querying was recently added")]
pub fn state(&'static self) -> State {
pub fn state(&'static self) -> LocalKeyState {
unsafe {
match (self.inner)().get() {
Some(cell) => {
match *cell.get() {
Some(..) => State::Valid,
None => State::Uninitialized,
Some(..) => LocalKeyState::Valid,
None => LocalKeyState::Uninitialized,
}
}
None => State::Destroyed,
None => LocalKeyState::Destroyed,
}
}
}
......@@ -327,7 +300,7 @@ pub fn state(&'static self) -> State {
#[unstable(feature = "std_misc")]
#[deprecated(since = "1.0.0",
reason = "function renamed to state() and returns more info")]
pub fn destroyed(&'static self) -> bool { self.state() == State::Destroyed }
pub fn destroyed(&'static self) -> bool { self.state() == LocalKeyState::Destroyed }
}
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
......@@ -553,7 +526,7 @@ mod tests {
use sync::mpsc::{channel, Sender};
use cell::UnsafeCell;
use super::State;
use super::LocalKeyState;
use thread;
struct Foo(Sender<()>);
......@@ -592,21 +565,21 @@ fn states() {
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
assert!(FOO.state() == State::Destroyed);
assert!(FOO.state() == LocalKeyState::Destroyed);
}
}
fn foo() -> Foo {
assert!(FOO.state() == State::Uninitialized);
assert!(FOO.state() == LocalKeyState::Uninitialized);
Foo
}
thread_local!(static FOO: Foo = foo());
thread::spawn(|| {
assert!(FOO.state() == State::Uninitialized);
assert!(FOO.state() == LocalKeyState::Uninitialized);
FOO.with(|_| {
assert!(FOO.state() == State::Valid);
assert!(FOO.state() == LocalKeyState::Valid);
});
assert!(FOO.state() == State::Valid);
assert!(FOO.state() == LocalKeyState::Valid);
}).join().ok().unwrap();
}
......@@ -642,7 +615,7 @@ impl Drop for S1 {
fn drop(&mut self) {
unsafe {
HITS += 1;
if K2.state() == State::Destroyed {
if K2.state() == LocalKeyState::Destroyed {
assert_eq!(HITS, 3);
} else {
if HITS == 1 {
......@@ -658,7 +631,7 @@ impl Drop for S2 {
fn drop(&mut self) {
unsafe {
HITS += 1;
assert!(K1.state() != State::Destroyed);
assert!(K1.state() != LocalKeyState::Destroyed);
assert_eq!(HITS, 2);
K1.with(|s| *s.get() = Some(S1));
}
......@@ -679,7 +652,7 @@ fn self_referential() {
impl Drop for S1 {
fn drop(&mut self) {
assert!(K1.state() == State::Destroyed);
assert!(K1.state() == LocalKeyState::Destroyed);
}
}
......@@ -702,7 +675,7 @@ impl Drop for S1 {
fn drop(&mut self) {
let S1(ref tx) = *self;
unsafe {
if K2.state() != State::Destroyed {
if K2.state() != LocalKeyState::Destroyed {
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
}
}
......
......@@ -138,9 +138,43 @@
//! synchronization primitives; the threads already provide basic blocking/signaling.
//!
//! * It can be implemented very efficiently on many platforms.
//!
//! ## Thread-local storage
//!
//! This module also provides an implementation of thread local storage for Rust
//! programs. Thread local storage is a method of storing data into a global
//! variable which each thread in the program will have its own copy of.
//! Threads do not share this data, so accesses do not need to be synchronized.
//!
//! At a high level, this module provides two variants of storage:
//!
//! * Owned thread-local storage. This is a type of thread local key which
//! owns the value that it contains, and will destroy the value when the
//! thread exits. This variant is created with the `thread_local!` macro and
//! can contain any value which is `'static` (no borrowed pointers).
//!
//! * Scoped thread-local storage. This type of key is used to store a reference
//! to a value into local storage temporarily for the scope of a function
//! call. There are no restrictions on what types of values can be placed
//! into this key.
//!
//! Both forms of thread local storage provide an accessor function, `with`,
//! which will yield a shared reference to the value to the specified
//! closure. Thread-local keys only allow shared access to values as there is no
//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
//! will want to make use of some form of **interior mutability** through the
//! `Cell` or `RefCell` types.
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::__local::{LocalKey, LocalKeyState};
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
pub use self::__scoped::ScopedKey;
use prelude::v1::*;
use any::Any;
......@@ -157,6 +191,22 @@
#[allow(deprecated)] use old_io::Writer;
////////////////////////////////////////////////////////////////////////////////
// Thread-local storage
////////////////////////////////////////////////////////////////////////////////
#[macro_use]
#[doc(hidden)]
#[path = "local.rs"] pub mod __local;
#[macro_use]
#[doc(hidden)]
#[path = "scoped.rs"] pub mod __scoped;
////////////////////////////////////////////////////////////////////////////////
// Builder
////////////////////////////////////////////////////////////////////////////////
/// Thread configuration. Provides detailed control over the properties
/// and behavior of new threads.
#[stable(feature = "rust1", since = "1.0.0")]
......@@ -322,6 +372,10 @@ fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> io::Result<JoinInner<T>> {
}
}
////////////////////////////////////////////////////////////////////////////////
// Free functions
////////////////////////////////////////////////////////////////////////////////
/// Spawn a new thread, returning a `JoinHandle` for it.
///
/// The join handle will implicitly *detach* the child thread upon being
......@@ -433,6 +487,10 @@ pub fn park_timeout(duration: Duration) {
*guard = false;
}
////////////////////////////////////////////////////////////////////////////////
// Thread
////////////////////////////////////////////////////////////////////////////////
/// The internal representation of a `Thread` handle
struct Inner {
name: Option<String>,
......@@ -557,6 +615,10 @@ impl thread_info::NewThread for Thread {
fn new(name: Option<String>) -> Thread { Thread::new(name) }
}
////////////////////////////////////////////////////////////////////////////////
// JoinHandle and JoinGuard
////////////////////////////////////////////////////////////////////////////////
/// Indicates the manner in which a thread exited.
///
/// A thread that completes without panicking is considered to exit successfully.
......@@ -689,6 +751,10 @@ fn drop(&mut self) {
}
}
////////////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod test {
use prelude::v1::*;
......
......@@ -38,9 +38,7 @@
//! });
//! ```
#![unstable(feature = "std_misc",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
#![unstable(feature = "thread_local_internals")]
use prelude::v1::*;
......@@ -58,7 +56,10 @@ pub mod __impl {
/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
/// and `with`, both of which currently use closures to control the scope of
/// their contents.
pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
/// Declare a new scoped thread local storage key.
///
......@@ -86,7 +87,7 @@ pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
target_os = "openbsd",
target_arch = "aarch64")),
thread_local)]
static $name: ::std::thread_local::scoped::Key<$t> =
static $name: ::std::thread::ScopedKey<$t> =
__scoped_thread_local_inner!($t);
);
(pub static $name:ident: $t:ty) => (
......@@ -96,11 +97,11 @@ pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
target_os = "openbsd",
target_arch = "aarch64")),
thread_local)]
pub static $name: ::std::thread_local::scoped::Key<$t> =
pub static $name: ::std::thread::ScopedKey<$t> =
__scoped_thread_local_inner!($t);
);
($t:ty) => ({
use std::thread_local::scoped::Key as __Key;
use std::thread::ScopedKey as __Key;
#[cfg(not(any(windows,
target_os = "android",
......@@ -108,7 +109,7 @@ pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
target_os = "openbsd",
target_arch = "aarch64")))]
const _INIT: __Key<$t> = __Key {
inner: ::std::thread_local::scoped::__impl::KeyInner {
inner: ::std::thread::__scoped::__impl::KeyInner {
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
}
};
......@@ -119,8 +120,8 @@ pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
target_os = "openbsd",
target_arch = "aarch64"))]
const _INIT: __Key<$t> = __Key {
inner: ::std::thread_local::scoped::__impl::KeyInner {
inner: ::std::thread_local::scoped::__impl::OS_INIT,
inner: ::std::thread::__scoped::__impl::KeyInner {
inner: ::std::thread::__scoped::__impl::OS_INIT,
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
}
};
......@@ -129,7 +130,10 @@ pub struct Key<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
})
}
impl<T> Key<T> {
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
impl<T> ScopedKey<T> {
/// Insert a value into this scoped thread local storage slot for a
/// duration of a closure.
///
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册