diff options
| author | Fenrir <[email protected]> | 2018-01-21 14:06:28 -0700 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-01-21 19:16:33 -0700 |
| commit | 23be3f4885688e5e0011005e2295c75168854c0a (patch) | |
| tree | dd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/sys_common/thread_local.rs | |
| parent | Update CI for Rust nightly-2017-12-01 + other fixes (diff) | |
| download | ctru-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.rs | 82 |
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()); + } } } |