diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 1488c7969f678..fbec96e9310f1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,30 +252,23 @@ pub mod num; /* 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; @@ -308,7 +301,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! diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index e4985e703ba76..90526b8f4f318 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -15,7 +15,7 @@ use core::prelude::*; 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 @@ thread_local! { static THREAD_INFO: RefCell> = RefCell::new(N impl ThreadInfo { fn with(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"); } diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread/local.rs similarity index 87% rename from src/libstd/thread_local/mod.rs rename to src/libstd/thread/local.rs index 08780292c88b1..43142d2e5bc0b 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread/local.rs @@ -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 { +pub struct LocalKey { // 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 { 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 @@ macro_rules! thread_local { 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 @@ macro_rules! thread_local { 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 @@ macro_rules! __thread_local_inner { #[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 @@ macro_rules! __thread_local_inner { }; #[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 @@ macro_rules! __thread_local_inner { #[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 Key { +impl LocalKey { /// 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 @@ impl Key { /// 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 @@ impl Key { #[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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { 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 @@ mod tests { impl Drop for S1 { fn drop(&mut self) { - assert!(K1.state() == State::Destroyed); + assert!(K1.state() == LocalKeyState::Destroyed); } } @@ -702,7 +675,7 @@ mod tests { 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()))); } } diff --git a/src/libstd/thread.rs b/src/libstd/thread/mod.rs similarity index 91% rename from src/libstd/thread.rs rename to src/libstd/thread/mod.rs index ab74442cac99f..57baeb1fb7486 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread/mod.rs @@ -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 @@ use time::Duration; #[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 @@ impl Builder { } } +//////////////////////////////////////////////////////////////////////////////// +// 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, @@ -557,6 +615,10 @@ impl thread_info::NewThread for Thread { fn new(name: Option) -> 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 @@ impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { } } +//////////////////////////////////////////////////////////////////////////////// +// Tests +//////////////////////////////////////////////////////////////////////////////// + #[cfg(test)] mod test { use prelude::v1::*; diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread/scoped.rs similarity index 91% rename from src/libstd/thread_local/scoped.rs rename to src/libstd/thread/scoped.rs index 86e6c059a70db..2a8be2ad82cea 100644 --- a/src/libstd/thread_local/scoped.rs +++ b/src/libstd/thread/scoped.rs @@ -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 { #[doc(hidden)] pub inner: __impl::KeyInner } +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully consider \ + stabilizing its interface")] +pub struct ScopedKey { #[doc(hidden)] pub inner: __impl::KeyInner } /// Declare a new scoped thread local storage key. /// @@ -86,7 +87,7 @@ macro_rules! __scoped_thread_local_inner { 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 @@ macro_rules! __scoped_thread_local_inner { 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 @@ macro_rules! __scoped_thread_local_inner { 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 @@ macro_rules! __scoped_thread_local_inner { 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 @@ macro_rules! __scoped_thread_local_inner { }) } -impl Key { +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully consider \ + stabilizing its interface")] +impl ScopedKey { /// Insert a value into this scoped thread local storage slot for a /// duration of a closure. ///