rollup merge of #23557: aturon/rfc-909
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
This commit is contained in:
commit
2153c581ef
5 changed files with 133 additions and 97 deletions
|
@ -252,30 +252,23 @@ pub mod num;
|
||||||
/* Runtime and platform support */
|
/* Runtime and platform support */
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod thread_local;
|
pub mod thread;
|
||||||
|
|
||||||
pub mod dynamic_lib;
|
|
||||||
pub mod ffi;
|
|
||||||
pub mod old_io;
|
|
||||||
pub mod io;
|
|
||||||
pub mod fs;
|
|
||||||
pub mod net;
|
|
||||||
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;
|
pub mod collections;
|
||||||
|
pub mod dynamic_lib;
|
||||||
/* Threads and communication */
|
pub mod env;
|
||||||
|
pub mod ffi;
|
||||||
pub mod thread;
|
pub mod fs;
|
||||||
|
pub mod io;
|
||||||
|
pub mod net;
|
||||||
|
pub mod old_io;
|
||||||
|
pub mod old_path;
|
||||||
|
pub mod os;
|
||||||
|
pub mod path;
|
||||||
|
pub mod process;
|
||||||
|
pub mod rand;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[path = "sys/common/mod.rs"] mod sys_common;
|
#[path = "sys/common/mod.rs"] mod sys_common;
|
||||||
|
@ -308,7 +301,7 @@ mod std {
|
||||||
pub use rt; // used for panic!()
|
pub use rt; // used for panic!()
|
||||||
pub use vec; // used for vec![]
|
pub use vec; // used for vec![]
|
||||||
pub use cell; // used for tls!
|
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 marker; // used for tls!
|
||||||
pub use ops; // used for bitflags!
|
pub use ops; // used for bitflags!
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use core::prelude::*;
|
||||||
use cell::RefCell;
|
use cell::RefCell;
|
||||||
use string::String;
|
use string::String;
|
||||||
use thread::Thread;
|
use thread::Thread;
|
||||||
use thread_local::State;
|
use thread::LocalKeyState;
|
||||||
|
|
||||||
struct ThreadInfo {
|
struct ThreadInfo {
|
||||||
stack_guard: uint,
|
stack_guard: uint,
|
||||||
|
@ -26,7 +26,7 @@ thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = RefCell::new(N
|
||||||
|
|
||||||
impl ThreadInfo {
|
impl ThreadInfo {
|
||||||
fn with<R, F>(f: F) -> R where F: FnOnce(&mut ThreadInfo) -> R {
|
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 \
|
panic!("Use of std::thread::current() is not possible after \
|
||||||
the thread's local data has been destroyed");
|
the thread's local data has been destroyed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,40 +9,13 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Thread local storage
|
//! 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 prelude::v1::*;
|
||||||
|
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod scoped;
|
|
||||||
|
|
||||||
// Sure wish we had macro hygiene, no?
|
// Sure wish we had macro hygiene, no?
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[unstable(feature = "thread_local_internals")]
|
#[unstable(feature = "thread_local_internals")]
|
||||||
|
@ -95,7 +68,7 @@ pub mod __impl {
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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
|
// 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
|
// 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
|
// address of another thread_local static. For this reason we kinda wonkily
|
||||||
|
@ -114,15 +87,15 @@ pub struct Key<T> {
|
||||||
pub init: fn() -> 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]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable]
|
||||||
macro_rules! thread_local {
|
macro_rules! thread_local {
|
||||||
(static $name:ident: $t:ty = $init:expr) => (
|
(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::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 as __Option;
|
||||||
use std::option::Option::None as __None;
|
use std::option::Option::None as __None;
|
||||||
|
|
||||||
|
@ -133,13 +106,13 @@ macro_rules! thread_local {
|
||||||
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
||||||
&__KEY
|
&__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: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::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 as __Option;
|
||||||
use std::option::Option::None as __None;
|
use std::option::Option::None as __None;
|
||||||
|
|
||||||
|
@ -150,7 +123,7 @@ macro_rules! thread_local {
|
||||||
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
|
||||||
&__KEY
|
&__KEY
|
||||||
}
|
}
|
||||||
::std::thread_local::Key { inner: __getit, init: __init }
|
::std::thread::LocalKey { inner: __getit, init: __init }
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -183,20 +156,20 @@ macro_rules! __thread_local_inner {
|
||||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||||
not(target_arch = "aarch64")),
|
not(target_arch = "aarch64")),
|
||||||
thread_local)]
|
thread_local)]
|
||||||
static $name: ::std::thread_local::__impl::KeyInner<$t> =
|
static $name: ::std::thread::__local::__impl::KeyInner<$t> =
|
||||||
__thread_local_inner!($init, $t);
|
__thread_local_inner!($init, $t);
|
||||||
);
|
);
|
||||||
(pub static $name:ident: $t:ty = $init:expr) => (
|
(pub static $name:ident: $t:ty = $init:expr) => (
|
||||||
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
#[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
|
||||||
not(target_arch = "aarch64")),
|
not(target_arch = "aarch64")),
|
||||||
thread_local)]
|
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);
|
__thread_local_inner!($init, $t);
|
||||||
);
|
);
|
||||||
($init:expr, $t:ty) => ({
|
($init:expr, $t:ty) => ({
|
||||||
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
|
#[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
|
||||||
const _INIT: ::std::thread_local::__impl::KeyInner<$t> = {
|
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||||
::std::thread_local::__impl::KeyInner {
|
::std::thread::__local::__impl::KeyInner {
|
||||||
inner: ::std::cell::UnsafeCell { value: $init },
|
inner: ::std::cell::UnsafeCell { value: $init },
|
||||||
dtor_registered: ::std::cell::UnsafeCell { value: false },
|
dtor_registered: ::std::cell::UnsafeCell { value: false },
|
||||||
dtor_running: ::std::cell::UnsafeCell { value: false },
|
dtor_running: ::std::cell::UnsafeCell { value: false },
|
||||||
|
@ -204,15 +177,15 @@ macro_rules! __thread_local_inner {
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
|
#[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) {
|
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 },
|
inner: ::std::cell::UnsafeCell { value: $init },
|
||||||
os: ::std::thread_local::__impl::OsStaticKey {
|
os: ::std::thread::__local::__impl::OsStaticKey {
|
||||||
inner: ::std::thread_local::__impl::OS_INIT_INNER,
|
inner: ::std::thread::__local::__impl::OS_INIT_INNER,
|
||||||
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
|
dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -226,7 +199,7 @@ macro_rules! __thread_local_inner {
|
||||||
#[unstable(feature = "std_misc",
|
#[unstable(feature = "std_misc",
|
||||||
reason = "state querying was recently added")]
|
reason = "state querying was recently added")]
|
||||||
#[derive(Eq, PartialEq, Copy)]
|
#[derive(Eq, PartialEq, Copy)]
|
||||||
pub enum State {
|
pub enum LocalKeyState {
|
||||||
/// All keys are in this state whenever a thread starts. Keys will
|
/// All keys are in this state whenever a thread starts. Keys will
|
||||||
/// transition to the `Valid` state once the first call to `with` happens
|
/// transition to the `Valid` state once the first call to `with` happens
|
||||||
/// and the initialization expression succeeds.
|
/// and the initialization expression succeeds.
|
||||||
|
@ -253,7 +226,7 @@ pub enum State {
|
||||||
Destroyed,
|
Destroyed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Key<T> {
|
impl<T: 'static> LocalKey<T> {
|
||||||
/// Acquire a reference to the value in this TLS key.
|
/// Acquire a reference to the value in this TLS key.
|
||||||
///
|
///
|
||||||
/// This will lazily initialize the value if this thread has not referenced
|
/// This will lazily initialize the value if this thread has not referenced
|
||||||
|
@ -309,16 +282,16 @@ impl<T: 'static> Key<T> {
|
||||||
/// any call to `with`.
|
/// any call to `with`.
|
||||||
#[unstable(feature = "std_misc",
|
#[unstable(feature = "std_misc",
|
||||||
reason = "state querying was recently added")]
|
reason = "state querying was recently added")]
|
||||||
pub fn state(&'static self) -> State {
|
pub fn state(&'static self) -> LocalKeyState {
|
||||||
unsafe {
|
unsafe {
|
||||||
match (self.inner)().get() {
|
match (self.inner)().get() {
|
||||||
Some(cell) => {
|
Some(cell) => {
|
||||||
match *cell.get() {
|
match *cell.get() {
|
||||||
Some(..) => State::Valid,
|
Some(..) => LocalKeyState::Valid,
|
||||||
None => State::Uninitialized,
|
None => LocalKeyState::Uninitialized,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => State::Destroyed,
|
None => LocalKeyState::Destroyed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +300,7 @@ impl<T: 'static> Key<T> {
|
||||||
#[unstable(feature = "std_misc")]
|
#[unstable(feature = "std_misc")]
|
||||||
#[deprecated(since = "1.0.0",
|
#[deprecated(since = "1.0.0",
|
||||||
reason = "function renamed to state() and returns more info")]
|
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")))]
|
#[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 sync::mpsc::{channel, Sender};
|
||||||
use cell::UnsafeCell;
|
use cell::UnsafeCell;
|
||||||
use super::State;
|
use super::LocalKeyState;
|
||||||
use thread;
|
use thread;
|
||||||
|
|
||||||
struct Foo(Sender<()>);
|
struct Foo(Sender<()>);
|
||||||
|
@ -592,21 +565,21 @@ mod tests {
|
||||||
struct Foo;
|
struct Foo;
|
||||||
impl Drop for Foo {
|
impl Drop for Foo {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(FOO.state() == State::Destroyed);
|
assert!(FOO.state() == LocalKeyState::Destroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn foo() -> Foo {
|
fn foo() -> Foo {
|
||||||
assert!(FOO.state() == State::Uninitialized);
|
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||||
Foo
|
Foo
|
||||||
}
|
}
|
||||||
thread_local!(static FOO: Foo = foo());
|
thread_local!(static FOO: Foo = foo());
|
||||||
|
|
||||||
thread::spawn(|| {
|
thread::spawn(|| {
|
||||||
assert!(FOO.state() == State::Uninitialized);
|
assert!(FOO.state() == LocalKeyState::Uninitialized);
|
||||||
FOO.with(|_| {
|
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();
|
}).join().ok().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +615,7 @@ mod tests {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
HITS += 1;
|
HITS += 1;
|
||||||
if K2.state() == State::Destroyed {
|
if K2.state() == LocalKeyState::Destroyed {
|
||||||
assert_eq!(HITS, 3);
|
assert_eq!(HITS, 3);
|
||||||
} else {
|
} else {
|
||||||
if HITS == 1 {
|
if HITS == 1 {
|
||||||
|
@ -658,7 +631,7 @@ mod tests {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
HITS += 1;
|
HITS += 1;
|
||||||
assert!(K1.state() != State::Destroyed);
|
assert!(K1.state() != LocalKeyState::Destroyed);
|
||||||
assert_eq!(HITS, 2);
|
assert_eq!(HITS, 2);
|
||||||
K1.with(|s| *s.get() = Some(S1));
|
K1.with(|s| *s.get() = Some(S1));
|
||||||
}
|
}
|
||||||
|
@ -679,7 +652,7 @@ mod tests {
|
||||||
|
|
||||||
impl Drop for S1 {
|
impl Drop for S1 {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(K1.state() == State::Destroyed);
|
assert!(K1.state() == LocalKeyState::Destroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,7 +675,7 @@ mod tests {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let S1(ref tx) = *self;
|
let S1(ref tx) = *self;
|
||||||
unsafe {
|
unsafe {
|
||||||
if K2.state() != State::Destroyed {
|
if K2.state() != LocalKeyState::Destroyed {
|
||||||
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
|
K2.with(|s| *s.get() = Some(Foo(tx.clone())));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -138,9 +138,43 @@
|
||||||
//! synchronization primitives; the threads already provide basic blocking/signaling.
|
//! synchronization primitives; the threads already provide basic blocking/signaling.
|
||||||
//!
|
//!
|
||||||
//! * It can be implemented very efficiently on many platforms.
|
//! * 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")]
|
||||||
|
|
||||||
|
#[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 prelude::v1::*;
|
||||||
|
|
||||||
use any::Any;
|
use any::Any;
|
||||||
|
@ -157,6 +191,22 @@ use time::Duration;
|
||||||
|
|
||||||
#[allow(deprecated)] use old_io::Writer;
|
#[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
|
/// Thread configuration. Provides detailed control over the properties
|
||||||
/// and behavior of new threads.
|
/// and behavior of new threads.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -322,6 +372,10 @@ impl Builder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Free functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Spawn a new thread, returning a `JoinHandle` for it.
|
/// Spawn a new thread, returning a `JoinHandle` for it.
|
||||||
///
|
///
|
||||||
/// The join handle will implicitly *detach* the child thread upon being
|
/// The join handle will implicitly *detach* the child thread upon being
|
||||||
|
@ -433,6 +487,10 @@ pub fn park_timeout(duration: Duration) {
|
||||||
*guard = false;
|
*guard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Thread
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// The internal representation of a `Thread` handle
|
/// The internal representation of a `Thread` handle
|
||||||
struct Inner {
|
struct Inner {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
|
@ -557,6 +615,10 @@ impl thread_info::NewThread for Thread {
|
||||||
fn new(name: Option<String>) -> Thread { Thread::new(name) }
|
fn new(name: Option<String>) -> Thread { Thread::new(name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// JoinHandle and JoinGuard
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Indicates the manner in which a thread exited.
|
/// Indicates the manner in which a thread exited.
|
||||||
///
|
///
|
||||||
/// A thread that completes without panicking is considered to exit successfully.
|
/// A thread that completes without panicking is considered to exit successfully.
|
||||||
|
@ -689,6 +751,10 @@ impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tests
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
|
@ -38,9 +38,7 @@
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![unstable(feature = "std_misc",
|
#![unstable(feature = "thread_local_internals")]
|
||||||
reason = "scoped TLS has yet to have wide enough use to fully consider \
|
|
||||||
stabilizing its interface")]
|
|
||||||
|
|
||||||
use prelude::v1::*;
|
use prelude::v1::*;
|
||||||
|
|
||||||
|
@ -58,7 +56,10 @@ pub mod __impl {
|
||||||
/// type `T` scoped to a particular lifetime. Keys provides two methods, `set`
|
/// 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
|
/// and `with`, both of which currently use closures to control the scope of
|
||||||
/// their contents.
|
/// 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.
|
/// Declare a new scoped thread local storage key.
|
||||||
///
|
///
|
||||||
|
@ -86,7 +87,7 @@ macro_rules! __scoped_thread_local_inner {
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
target_arch = "aarch64")),
|
target_arch = "aarch64")),
|
||||||
thread_local)]
|
thread_local)]
|
||||||
static $name: ::std::thread_local::scoped::Key<$t> =
|
static $name: ::std::thread::ScopedKey<$t> =
|
||||||
__scoped_thread_local_inner!($t);
|
__scoped_thread_local_inner!($t);
|
||||||
);
|
);
|
||||||
(pub static $name:ident: $t:ty) => (
|
(pub static $name:ident: $t:ty) => (
|
||||||
|
@ -96,11 +97,11 @@ macro_rules! __scoped_thread_local_inner {
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
target_arch = "aarch64")),
|
target_arch = "aarch64")),
|
||||||
thread_local)]
|
thread_local)]
|
||||||
pub static $name: ::std::thread_local::scoped::Key<$t> =
|
pub static $name: ::std::thread::ScopedKey<$t> =
|
||||||
__scoped_thread_local_inner!($t);
|
__scoped_thread_local_inner!($t);
|
||||||
);
|
);
|
||||||
($t:ty) => ({
|
($t:ty) => ({
|
||||||
use std::thread_local::scoped::Key as __Key;
|
use std::thread::ScopedKey as __Key;
|
||||||
|
|
||||||
#[cfg(not(any(windows,
|
#[cfg(not(any(windows,
|
||||||
target_os = "android",
|
target_os = "android",
|
||||||
|
@ -108,7 +109,7 @@ macro_rules! __scoped_thread_local_inner {
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
target_arch = "aarch64")))]
|
target_arch = "aarch64")))]
|
||||||
const _INIT: __Key<$t> = __Key {
|
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 _ },
|
inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -119,8 +120,8 @@ macro_rules! __scoped_thread_local_inner {
|
||||||
target_os = "openbsd",
|
target_os = "openbsd",
|
||||||
target_arch = "aarch64"))]
|
target_arch = "aarch64"))]
|
||||||
const _INIT: __Key<$t> = __Key {
|
const _INIT: __Key<$t> = __Key {
|
||||||
inner: ::std::thread_local::scoped::__impl::KeyInner {
|
inner: ::std::thread::__scoped::__impl::KeyInner {
|
||||||
inner: ::std::thread_local::scoped::__impl::OS_INIT,
|
inner: ::std::thread::__scoped::__impl::OS_INIT,
|
||||||
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
|
marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -129,7 +130,10 @@ macro_rules! __scoped_thread_local_inner {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// Insert a value into this scoped thread local storage slot for a
|
||||||
/// duration of a closure.
|
/// duration of a closure.
|
||||||
///
|
///
|
Loading…
Add table
Add a link
Reference in a new issue