diff options
| author | Eduard Burtescu <edy.burt@gmail.com> | 2015-05-27 11:18:36 +0300 |
|---|---|---|
| committer | Eduard Burtescu <edy.burt@gmail.com> | 2015-05-27 11:19:03 +0300 |
| commit | 377b0900aede976b2d37a499bbd7b62c2e39b358 (patch) | |
| tree | b4a5a4431d36ed1a4e0a39c7d2ef2563ecac9bf4 /src/libstd/thread | |
| parent | 6e8e4f847c2ea02fec021ea15dfb2de6beac797a (diff) | |
| download | rust-377b0900aede976b2d37a499bbd7b62c2e39b358.tar.gz rust-377b0900aede976b2d37a499bbd7b62c2e39b358.zip | |
Use `const fn` to abstract away the contents of UnsafeCell & friends.
Diffstat (limited to 'src/libstd/thread')
| -rw-r--r-- | src/libstd/thread/local.rs | 246 | ||||
| -rw-r--r-- | src/libstd/thread/mod.rs | 3 | ||||
| -rw-r--r-- | src/libstd/thread/scoped_tls.rs | 91 |
3 files changed, 114 insertions, 226 deletions
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 2e043c58a5d..0eafd4d5f12 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -18,12 +18,7 @@ use cell::UnsafeCell; // Sure wish we had macro hygiene, no? #[doc(hidden)] -pub mod __impl { - pub use super::imp::Key as KeyInner; - pub use super::imp::destroy_value; - pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER; - pub use sys_common::thread_local::StaticKey as OsStaticKey; -} +pub use self::imp::Key as __KeyInner; /// A thread local storage key which owns its contents. /// @@ -76,55 +71,10 @@ pub struct LocalKey<T> { // // This is trivially devirtualizable by LLVM because we never store anything // to this field and rustc can declare the `static` as constant as well. - #[doc(hidden)] - pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>, + inner: fn() -> &'static __KeyInner<T>, // initialization routine to invoke to create a value - #[doc(hidden)] - pub init: fn() -> T, -} - -/// Declare a new thread local storage key of type `std::thread::LocalKey`. -/// -/// See [LocalKey documentation](thread/struct.LocalKey.html) for more information. -#[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::LocalKey<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread::__local::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::Option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }); - fn __init() -> $t { $init } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { - &__KEY - } - ::std::thread::LocalKey { inner: __getit, init: __init } - }; - ); - (pub static $name:ident: $t:ty = $init:expr) => ( - pub static $name: ::std::thread::LocalKey<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread::__local::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::Option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }); - fn __init() -> $t { $init } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { - &__KEY - } - ::std::thread::LocalKey { inner: __getit, init: __init } - }; - ); + init: fn() -> T, } // Macro pain #4586: @@ -147,50 +97,37 @@ macro_rules! thread_local { // To get around this, we're forced to inject the #[cfg] logic into the macro // itself. Woohoo. +/// Declare a new thread local storage key of type `std::thread::LocalKey`. +/// +/// See [LocalKey documentation](thread/struct.LocalKey.html) for more information. #[macro_export] -#[doc(hidden)] +#[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] -macro_rules! __thread_local_inner { +macro_rules! thread_local { (static $name:ident: $t:ty = $init:expr) => ( - #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), - not(target_arch = "aarch64")), - thread_local)] - static $name: ::std::thread::__local::KeyInner<$t> = - __thread_local_inner!($init, $t); + static $name: ::std::thread::LocalKey<$t> = { + #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), + not(target_arch = "aarch64")), + thread_local)] + static __KEY: ::std::thread::__LocalKeyInner<$t> = + ::std::thread::__LocalKeyInner::new(); + fn __init() -> $t { $init } + fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY } + ::std::thread::LocalKey::new(__getit, __init) + }; ); (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::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::KeyInner<$t> = { - ::std::thread::__local::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - dtor_registered: ::std::cell::UnsafeCell { value: false }, - dtor_running: ::std::cell::UnsafeCell { value: false }, - } - }; - - #[allow(trivial_casts)] - #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] - const _INIT: ::std::thread::__local::KeyInner<$t> = { - ::std::thread::__local::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - os: ::std::thread::__local::OsStaticKey { - inner: ::std::thread::__local::OS_INIT_INNER, - dtor: ::std::option::Option::Some( - ::std::thread::__local::destroy_value::<$t> - ), - }, - } + pub static $name: ::std::thread::LocalKey<$t> = { + #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), + not(target_arch = "aarch64")), + thread_local)] + static __KEY: ::std::thread::__LocalKeyInner<$t> = + ::std::thread::__LocalKeyInner::new(); + fn __init() -> $t { $init } + fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY } + ::std::thread::LocalKey::new(__getit, __init) }; - - _INIT - }); + ); } /// Indicator of the state of a thread local storage key. @@ -225,6 +162,14 @@ pub enum LocalKeyState { } impl<T: 'static> LocalKey<T> { + #[doc(hidden)] + pub const fn new(inner: fn() -> &'static __KeyInner<T>, init: fn() -> T) -> LocalKey<T> { + LocalKey { + inner: inner, + init: init + } + } + /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced @@ -300,44 +245,45 @@ impl<T: 'static> LocalKey<T> { mod imp { use prelude::v1::*; - use cell::UnsafeCell; + use cell::{Cell, UnsafeCell}; use intrinsics; - use ptr; pub struct Key<T> { - // Place the inner bits in an `UnsafeCell` to currently get around the - // "only Sync statics" restriction. This allows any type to be placed in - // the cell. - // - // Note that all access requires `T: 'static` so it can't be a type with - // any borrowed pointers still. - pub inner: UnsafeCell<T>, + inner: UnsafeCell<Option<T>>, // Metadata to keep track of the state of the destructor. Remember that // these variables are thread-local, not global. - pub dtor_registered: UnsafeCell<bool>, // should be Cell - pub dtor_running: UnsafeCell<bool>, // should be Cell + dtor_registered: Cell<bool>, + dtor_running: Cell<bool>, } unsafe impl<T> ::marker::Sync for Key<T> { } impl<T> Key<T> { - pub unsafe fn get(&'static self) -> Option<&'static T> { - if intrinsics::needs_drop::<T>() && *self.dtor_running.get() { + pub const fn new() -> Key<T> { + Key { + inner: UnsafeCell::new(None), + dtor_registered: Cell::new(false), + dtor_running: Cell::new(false) + } + } + + pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { + if intrinsics::needs_drop::<T>() && self.dtor_running.get() { return None } self.register_dtor(); - Some(&*self.inner.get()) + Some(&self.inner) } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() { + if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { return } register_dtor(self as *const _ as *mut u8, destroy_value::<T>); - *self.dtor_registered.get() = true; + self.dtor_registered.set(true); } } @@ -354,6 +300,7 @@ mod imp { unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { use boxed; use mem; + use ptr; use libc; use sys_common::thread_local as os; @@ -381,10 +328,7 @@ mod imp { // *should* be the case that this loop always terminates because we // provide the guarantee that a TLS key cannot be set after it is // flagged for destruction. - static DTORS: os::StaticKey = os::StaticKey { - inner: os::INIT_INNER, - dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)), - }; + static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; if DTORS.get().is_null() { let v: Box<List> = box Vec::new(); @@ -422,8 +366,8 @@ mod imp { // Right before we run the user destructor be sure to flag the // destructor as running for this thread so calls to `get` will return // `None`. - *(*ptr).dtor_running.get() = true; - ptr::read((*ptr).inner.get()); + (*ptr).dtor_running.set(true); + intrinsics::drop_in_place((*ptr).inner.get()); } } @@ -433,54 +377,50 @@ mod imp { use prelude::v1::*; use alloc::boxed; - use cell::UnsafeCell; - use mem; + use cell::{Cell, UnsafeCell}; + use marker; use ptr; use sys_common::thread_local::StaticKey as OsStaticKey; pub struct Key<T> { - // Statically allocated initialization expression, using an `UnsafeCell` - // for the same reasons as above. - pub inner: UnsafeCell<T>, - // OS-TLS key that we'll use to key off. - pub os: OsStaticKey, + os: OsStaticKey, + marker: marker::PhantomData<Cell<T>>, } unsafe impl<T> ::marker::Sync for Key<T> { } struct Value<T: 'static> { key: &'static Key<T>, - value: T, + value: UnsafeCell<Option<T>>, } - impl<T> Key<T> { - pub unsafe fn get(&'static self) -> Option<&'static T> { - self.ptr().map(|p| &*p) + impl<T: 'static> Key<T> { + pub const fn new() -> Key<T> { + Key { + os: OsStaticKey::new(Some(destroy_value::<T>)), + marker: marker::PhantomData + } } - unsafe fn ptr(&'static self) -> Option<*mut T> { + pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { let ptr = self.os.get() as *mut Value<T>; if !ptr.is_null() { if ptr as usize == 1 { return None } - return Some(&mut (*ptr).value as *mut T); + return Some(&(*ptr).value); } // If the lookup returned null, we haven't initialized our own local // copy, so do that now. - // - // Also note that this transmute_copy should be ok because the value - // `inner` is already validated to be a valid `static` value, so we - // should be able to freely copy the bits. let ptr: Box<Value<T>> = box Value { key: self, - value: mem::transmute_copy(&self.inner), + value: UnsafeCell::new(None), }; let ptr = boxed::into_raw(ptr); self.os.set(ptr as *mut u8); - Some(&mut (*ptr).value as *mut T) + Some(&(*ptr).value) } } @@ -505,7 +445,7 @@ mod tests { use prelude::v1::*; use sync::mpsc::{channel, Sender}; - use cell::UnsafeCell; + use cell::{Cell, UnsafeCell}; use super::LocalKeyState; use thread; @@ -520,23 +460,23 @@ mod tests { #[test] fn smoke_no_dtor() { - thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 }); + thread_local!(static FOO: Cell<i32> = Cell::new(1)); - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 1); - *f.get() = 2; + FOO.with(|f| { + assert_eq!(f.get(), 1); + f.set(2); }); let (tx, rx) = channel(); let _t = thread::spawn(move|| { - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 1); + FOO.with(|f| { + assert_eq!(f.get(), 1); }); tx.send(()).unwrap(); }); rx.recv().unwrap(); - FOO.with(|f| unsafe { - assert_eq!(*f.get(), 2); + FOO.with(|f| { + assert_eq!(f.get(), 2); }); } @@ -565,9 +505,7 @@ mod tests { #[test] fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell { - value: None - }); + thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None)); let (tx, rx) = channel(); let _t = thread::spawn(move|| unsafe { @@ -583,12 +521,8 @@ mod tests { fn circular() { struct S1; struct S2; - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell { - value: None - }); - thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell { - value: None - }); + thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None)); static mut HITS: u32 = 0; impl Drop for S1 { @@ -626,9 +560,7 @@ mod tests { #[test] fn self_referential() { struct S1; - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell { - value: None - }); + thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); impl Drop for S1 { fn drop(&mut self) { @@ -644,12 +576,8 @@ mod tests { #[test] fn dtors_in_dtors_in_dtors() { struct S1(Sender<()>); - thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell { - value: None - }); - thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell { - value: None - }); + thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None)); impl Drop for S1 { fn drop(&mut self) { diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 7c8cb5b01c1..f090d3e77dd 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -216,8 +216,7 @@ pub use self::local::{LocalKey, LocalKeyState}; consider stabilizing its interface")] pub use self::scoped_tls::ScopedKey; -#[doc(hidden)] pub use self::local::__impl as __local; -#[doc(hidden)] pub use self::scoped_tls::__impl as __scoped; +#[doc(hidden)] pub use self::local::__KeyInner as __LocalKeyInner; //////////////////////////////////////////////////////////////////////////////// // Builder diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index e195c3aaa3f..dda1db9aece 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -43,13 +43,6 @@ use prelude::v1::*; -// macro hygiene sure would be nice, wouldn't it? -#[doc(hidden)] -pub mod __impl { - pub use super::imp::KeyInner; - pub use sys_common::thread_local::INIT as OS_INIT; -} - /// Type representing a thread local storage key corresponding to a reference /// to the type parameter `T`. /// @@ -60,7 +53,7 @@ pub mod __impl { #[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> } +pub struct ScopedKey<T> { inner: imp::KeyInner<T> } /// Declare a new scoped thread local storage key. /// @@ -72,18 +65,6 @@ pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> } #[allow_internal_unstable] macro_rules! scoped_thread_local { (static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(static $name: $t); - ); - (pub static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(pub static $name: $t); - ); -} - -#[macro_export] -#[doc(hidden)] -#[allow_internal_unstable] -macro_rules! __scoped_thread_local_inner { - (static $name:ident: $t:ty) => ( #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios", @@ -91,7 +72,7 @@ macro_rules! __scoped_thread_local_inner { target_arch = "aarch64")), thread_local)] static $name: ::std::thread::ScopedKey<$t> = - __scoped_thread_local_inner!($t); + ::std::thread::ScopedKey::new(); ); (pub static $name:ident: $t:ty) => ( #[cfg_attr(not(any(windows, @@ -101,42 +82,19 @@ macro_rules! __scoped_thread_local_inner { target_arch = "aarch64")), thread_local)] pub static $name: ::std::thread::ScopedKey<$t> = - __scoped_thread_local_inner!($t); + ::std::thread::ScopedKey::new(); ); - ($t:ty) => ({ - use std::thread::ScopedKey as __Key; - - #[cfg(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")))] - const _INIT: __Key<$t> = __Key { - inner: ::std::thread::__scoped::KeyInner { - inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, - } - }; - - #[cfg(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64"))] - const _INIT: __Key<$t> = __Key { - inner: ::std::thread::__scoped::KeyInner { - inner: ::std::thread::__scoped::OS_INIT, - marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>, - } - }; - - _INIT - }) } #[unstable(feature = "scoped_tls", reason = "scoped TLS has yet to have wide enough use to fully consider \ stabilizing its interface")] impl<T> ScopedKey<T> { + #[doc(hidden)] + pub const fn new() -> ScopedKey<T> { + ScopedKey { inner: imp::KeyInner::new() } + } + /// Inserts a value into this scoped thread local storage slot for a /// duration of a closure. /// @@ -170,7 +128,7 @@ impl<T> ScopedKey<T> { F: FnOnce() -> R, { struct Reset<'a, T: 'a> { - key: &'a __impl::KeyInner<T>, + key: &'a imp::KeyInner<T>, val: *mut T, } impl<'a, T> Drop for Reset<'a, T> { @@ -231,19 +189,18 @@ impl<T> ScopedKey<T> { target_os = "openbsd", target_arch = "aarch64")))] mod imp { - use std::cell::UnsafeCell; + use std::cell::Cell; - #[doc(hidden)] - pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> } + pub struct KeyInner<T> { inner: Cell<*mut T> } unsafe impl<T> ::marker::Sync for KeyInner<T> { } - #[doc(hidden)] impl<T> KeyInner<T> { - #[doc(hidden)] - pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; } - #[doc(hidden)] - pub unsafe fn get(&self) -> *mut T { *self.inner.get() } + pub const fn new() -> KeyInner<T> { + KeyInner { inner: Cell::new(0 as *mut _) } + } + pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr); } + pub unsafe fn get(&self) -> *mut T { self.inner.get() } } } @@ -253,23 +210,27 @@ mod imp { target_os = "openbsd", target_arch = "aarch64"))] mod imp { + use prelude::v1::*; + + use cell::Cell; use marker; - use std::cell::Cell; use sys_common::thread_local::StaticKey as OsStaticKey; - #[doc(hidden)] pub struct KeyInner<T> { pub inner: OsStaticKey, pub marker: marker::PhantomData<Cell<T>>, } - unsafe impl<T> ::marker::Sync for KeyInner<T> { } + unsafe impl<T> marker::Sync for KeyInner<T> { } - #[doc(hidden)] impl<T> KeyInner<T> { - #[doc(hidden)] + pub const fn new() -> KeyInner<T> { + KeyInner { + inner: OsStaticKey::new(None), + marker: marker::PhantomData + } + } pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) } - #[doc(hidden)] pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ } } } |
