diff options
Diffstat (limited to 'src/libstd/sys_common')
| -rw-r--r-- | src/libstd/sys_common/mod.rs | 3 | ||||
| -rw-r--r-- | src/libstd/sys_common/thread_local_dtor.rs | 49 | ||||
| -rw-r--r-- | src/libstd/sys_common/thread_local_key.rs (renamed from src/libstd/sys_common/thread_local.rs) | 39 |
3 files changed, 54 insertions, 37 deletions
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index e03e0fc8345..e57bb267cbd 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -65,7 +65,8 @@ pub mod remutex; pub mod rwlock; pub mod thread; pub mod thread_info; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod util; pub mod wtf8; diff --git a/src/libstd/sys_common/thread_local_dtor.rs b/src/libstd/sys_common/thread_local_dtor.rs new file mode 100644 index 00000000000..6f5ebf4a271 --- /dev/null +++ b/src/libstd/sys_common/thread_local_dtor.rs @@ -0,0 +1,49 @@ +//! Thread-local destructor +//! +//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store +//! with an associated destructor), many platforms also provide thread-local +//! destructors that are not associated with any particular data. These are +//! often more efficient. +//! +//! This module provides a fallback implementation for that interface, based +//! on the less efficient thread-local "keys". Each platform provides +//! a `thread_local_dtor` module which will either re-export the fallback, +//! or implement something more efficient. + +#![unstable(feature = "thread_local_internals", issue = "none")] +#![allow(dead_code)] // sys isn't exported yet + +use crate::ptr; +use crate::sys_common::thread_local_key::StaticKey; + +pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" 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 "C" 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 "C" 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()); + } + } +} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local_key.rs index 756b8d044a2..ac5b128298d 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local_key.rs @@ -4,7 +4,7 @@ //! using the native OS-provided facilities (think `TlsAlloc` or //! `pthread_setspecific`). The interface of this differs from the other types //! of thread-local-storage provided in this crate in that OS-based TLS can only -//! get/set pointers, +//! get/set pointer-sized data, possibly with an associated destructor. //! //! This module also provides two flavors of TLS. One is intended for static //! initialization, and does not contain a `Drop` implementation to deallocate @@ -14,7 +14,7 @@ //! # Usage //! //! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::spawn::Key` are likely much +//! being built on. Types such as `thread_local::spawn::Key` are likely much //! more useful in practice than this OS-based version which likely requires //! unsafe code to interoperate with. //! @@ -48,9 +48,8 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] // sys isn't exported yet -use crate::ptr; use crate::sync::atomic::{self, AtomicUsize, Ordering}; -use crate::sys::thread_local as imp; +use crate::sys::thread_local_key as imp; use crate::sys_common::mutex::Mutex; /// A type for TLS keys that are statically allocated. @@ -233,38 +232,6 @@ impl Drop for Key { } } -pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" 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 "C" 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 "C" 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()); - } - } -} - #[cfg(test)] mod tests { use super::{Key, StaticKey}; |
