]> git.lizzy.rs Git - rust.git/blobdiff - src/libstd/sys_common/thread_local.rs
Auto merge of #43710 - zackmdavis:field_init_shorthand_power_slam, r=Mark-Simulacrum
[rust.git] / src / libstd / sys_common / thread_local.rs
index 25a9d5720d9338bfb14ed8dba43bd03edaf36362..87ffd304e1a33b0bf2a44ccd602cdfc4e1ad8d1b 100644 (file)
@@ -33,7 +33,7 @@
 //! Using a dynamically allocated TLS key. Note that this key can be shared
 //! among many threads via an `Arc`.
 //!
-//! ```rust,ignore
+//! ```ignore (cannot-doctest-private-modules)
 //! let key = Key::new(None);
 //! assert!(key.get().is_null());
 //! key.set(1 as *mut u8);
@@ -45,7 +45,7 @@
 //! Sometimes a statically allocated key is either required or easier to work
 //! with, however.
 //!
-//! ```rust,ignore
+//! ```ignore (cannot-doctest-private-modules)
 //! static KEY: StaticKey = INIT;
 //!
 //! unsafe {
 #![unstable(feature = "thread_local_internals", issue = "0")]
 #![allow(dead_code)] // sys isn't exported yet
 
+use ptr;
 use sync::atomic::{self, AtomicUsize, Ordering};
-
 use sys::thread_local as imp;
+use sys_common::mutex::Mutex;
 
 /// A type for TLS keys that are statically allocated.
 ///
@@ -73,7 +74,7 @@
 ///
 /// # Examples
 ///
-/// ```ignore
+/// ```ignore (cannot-doctest-private-modules)
 /// use tls::os::{StaticKey, INIT};
 ///
 /// static KEY: StaticKey = INIT;
@@ -104,7 +105,7 @@ pub struct StaticKey {
 ///
 /// # Examples
 ///
-/// ```rust,ignore
+/// ```ignore (cannot-doctest-private-modules)
 /// use tls::os::Key;
 ///
 /// let key = Key::new(None);
@@ -127,7 +128,7 @@ impl StaticKey {
     pub const fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> StaticKey {
         StaticKey {
             key: atomic::AtomicUsize::new(0),
-            dtor: dtor
+            dtor,
         }
     }
 
@@ -145,20 +146,6 @@ pub unsafe fn get(&self) -> *mut u8 { imp::get(self.key()) }
     #[inline]
     pub unsafe fn set(&self, val: *mut u8) { imp::set(self.key(), val) }
 
-    /// Deallocates this OS TLS key.
-    ///
-    /// This function is unsafe as there is no guarantee that the key is not
-    /// currently in use by other threads or will not ever be used again.
-    ///
-    /// Note that this does *not* run the user-provided destructor if one was
-    /// specified at definition time. Doing so must be done manually.
-    pub unsafe fn destroy(&self) {
-        match self.key.swap(0, Ordering::SeqCst) {
-            0 => {}
-            n => { imp::destroy(n as imp::Key) }
-        }
-    }
-
     #[inline]
     unsafe fn key(&self) -> imp::Key {
         match self.key.load(Ordering::Relaxed) {
@@ -168,6 +155,24 @@ unsafe fn key(&self) -> imp::Key {
     }
 
     unsafe fn lazy_init(&self) -> usize {
+        // Currently the Windows implementation of TLS is pretty hairy, and
+        // it greatly simplifies creation if we just synchronize everything.
+        //
+        // Additionally a 0-index of a tls key hasn't been seen on windows, so
+        // we just simplify the whole branch.
+        if imp::requires_synchronized_create() {
+            static INIT_LOCK: Mutex = Mutex::new();
+            INIT_LOCK.lock();
+            let mut key = self.key.load(Ordering::SeqCst);
+            if key == 0 {
+                key = imp::create(self.dtor) as usize;
+                self.key.store(key, Ordering::SeqCst);
+            }
+            INIT_LOCK.unlock();
+            assert!(key != 0);
+            return key
+        }
+
         // POSIX allows the key created here to be 0, but the compare_and_swap
         // below relies on using 0 as a sentinel value to check who won the
         // race to set the shared TLS key. As far as I know, there is no
@@ -227,7 +232,42 @@ pub fn set(&self, val: *mut u8) {
 
 impl Drop for Key {
     fn drop(&mut self) {
-        unsafe { imp::destroy(self.key) }
+        // Right now Windows doesn't support TLS key destruction, but this also
+        // isn't used anywhere other than tests, so just leak the TLS key.
+        // unsafe { imp::destroy(self.key) }
+    }
+}
+
+pub unsafe fn register_dtor_fallback(t: *mut u8,
+                                     dtor: unsafe extern fn(*mut u8)) {
+    // The fallback implementation uses a vanilla OS-based TLS key to track
+    // the list of destructors that need to be run for this thread. The key
+    // then has its own destructor which runs all the other destructors.
+    //
+    // The destructor for DTORS is a little special in that it has a `while`
+    // loop to continuously drain the list of registered destructors. It
+    // *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: StaticKey = 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();
+        DTORS.set(Box::into_raw(v) as *mut u8);
+    }
+    let list: &mut List = &mut *(DTORS.get() as *mut List);
+    list.push((t, dtor));
+
+    unsafe extern fn run_dtors(mut ptr: *mut u8) {
+        while !ptr.is_null() {
+            let list: Box<List> = Box::from_raw(ptr as *mut List);
+            for &(ptr, dtor) in list.iter() {
+                dtor(ptr);
+            }
+            ptr = DTORS.get();
+            DTORS.set(ptr::null_mut());
+        }
     }
 }