aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys_common/thread_local.rs
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/sys_common/thread_local.rs
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz
ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/sys_common/thread_local.rs')
-rw-r--r--ctr-std/src/sys_common/thread_local.rs82
1 files changed, 61 insertions, 21 deletions
diff --git a/ctr-std/src/sys_common/thread_local.rs b/ctr-std/src/sys_common/thread_local.rs
index 25a9d57..a4aa3d9 100644
--- a/ctr-std/src/sys_common/thread_local.rs
+++ b/ctr-std/src/sys_common/thread_local.rs
@@ -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 {
@@ -58,9 +58,10 @@
#![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 @@ use sys::thread_local as imp;
///
/// # 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 @@ impl StaticKey {
#[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 @@ impl StaticKey {
}
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 @@ impl Key {
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.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.get();
+ DTORS.set(ptr::null_mut());
+ }
}
}