about summary refs log tree commit diff
path: root/src/libstd/thread
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2015-05-27 11:18:36 +0300
committerEduard Burtescu <edy.burt@gmail.com>2015-05-27 11:19:03 +0300
commit377b0900aede976b2d37a499bbd7b62c2e39b358 (patch)
treeb4a5a4431d36ed1a4e0a39c7d2ef2563ecac9bf4 /src/libstd/thread
parent6e8e4f847c2ea02fec021ea15dfb2de6beac797a (diff)
downloadrust-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.rs246
-rw-r--r--src/libstd/thread/mod.rs3
-rw-r--r--src/libstd/thread/scoped_tls.rs91
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 _ }
     }
 }