about summary refs log tree commit diff
path: root/src/libstd/sys_common
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-06-24 04:42:18 +0000
committerbors <bors@rust-lang.org>2017-06-24 04:42:18 +0000
commit1ccc330d4b4741bbc0388fb55eb37b7b94f903d5 (patch)
treeaaade9b315e98c22d41c6772b4808fbf494ea365 /src/libstd/sys_common
parent229d0d3266002d343cdd2f4a3bf7f2fe9da15f38 (diff)
parent06540cb205545e5e7e509933af27142ca35eae17 (diff)
downloadrust-1ccc330d4b4741bbc0388fb55eb37b7b94f903d5.tar.gz
rust-1ccc330d4b4741bbc0388fb55eb37b7b94f903d5.zip
Auto merge of #42687 - alexcrichton:windows-tls, r=sfackler
rustc: Enable #[thread_local] for Windows

I think LLVM has had support for quite some time now for this, we just never got
around to testing it out and binding it. We've had some trouble landing this in
the past I believe, but it's time to try again!

This commit flags the `#[thread_local]` attribute as being available for Windows
targets and adds an implementation of `register_dtor` in the `thread::local`
module to ensure we can destroy these keys. The same functionality is
implemented in clang via a function called `__tlregdtor` (presumably provided in
some Windows runtime somewhere), but this function unfortunately does not take a
data pointer (just a thunk) which means we can't easily call it. For now
destructors are just run in the same way the Linux fallback is implemented,
which is just keeping track via a single OS-based TLS key.
Diffstat (limited to 'src/libstd/sys_common')
-rw-r--r--src/libstd/sys_common/thread_local.rs35
1 files changed, 34 insertions, 1 deletions
diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local.rs
index 9ba023b57e6..1f889c70707 100644
--- a/src/libstd/sys_common/thread_local.rs
+++ b/src/libstd/sys_common/thread_local.rs
@@ -58,8 +58,8 @@
 #![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;
 
@@ -238,6 +238,39 @@ impl Drop for 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());
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::{Key, StaticKey};