Rollup merge of #74263 - RalfJung:thread-local, r=Mark-Simulacrum
Slight reorganization of sys/(fast_)thread_local I was long confused by the `thread_local` and `fast_thread_local` modules in the `sys(_common)` part of libstd. The names make it *sound* like `fast_thread_local` is just a faster version of `thread_local`, but really these are totally different APIs: one provides thread-local "keys", which are non-addressable pointer-sized pieces of local storage with an associated destructor; the other (the "fast" one) provides just a destructor. So I propose we rename `fast_thread_local` to `thread_local_dtor`, and `thread_local` to `thread_local_key`. That's what this PR does.
This commit is contained in:
commit
fadd91c630
23 changed files with 83 additions and 67 deletions
|
@ -16,8 +16,8 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
#[path = "../unix/thread_local.rs"]
|
||||
pub mod thread_local;
|
||||
#[path = "../unix/thread_local_key.rs"]
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
|
|
|
@ -22,7 +22,6 @@ pub mod cmath;
|
|||
pub mod condvar;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fast_thread_local;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
|
@ -37,7 +36,8 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
use crate::io::ErrorKind;
|
||||
|
|
|
@ -2,25 +2,25 @@ pub type Key = usize;
|
|||
|
||||
#[inline]
|
||||
pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
|
||||
panic!("should not be used on the wasm target");
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn set(_key: Key, _value: *mut u8) {
|
||||
panic!("should not be used on the wasm target");
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get(_key: Key) -> *mut u8 {
|
||||
panic!("should not be used on the wasm target");
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn destroy(_key: Key) {
|
||||
panic!("should not be used on the wasm target");
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn requires_synchronized_create() -> bool {
|
||||
panic!("should not be used on the wasm target");
|
||||
panic!("should not be used on the hermit target");
|
||||
}
|
|
@ -30,7 +30,7 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
|
|
|
@ -47,7 +47,6 @@ pub mod cmath;
|
|||
pub mod condvar;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fast_thread_local;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
|
@ -68,7 +67,8 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#![cfg(target_thread_local)]
|
||||
#![unstable(feature = "thread_local_internals", issue = "none")]
|
||||
|
||||
//! Provides thread-local destructors without an associated "key", which
|
||||
//! can be more efficient.
|
||||
|
||||
// Since what appears to be glibc 2.18 this symbol has been shipped which
|
||||
// GCC and clang both use to invoke destructors in thread_local globals, so
|
||||
// let's do the same!
|
||||
|
@ -16,7 +19,7 @@
|
|||
))]
|
||||
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||
use crate::mem;
|
||||
use crate::sys_common::thread_local::register_dtor_fallback;
|
||||
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
|
||||
|
||||
extern "C" {
|
||||
#[linkage = "extern_weak"]
|
|
@ -13,7 +13,6 @@ pub mod cmath;
|
|||
pub mod condvar;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fast_thread_local;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
|
@ -29,7 +28,8 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
|
|
|
@ -5,7 +5,3 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
|||
use crate::sys_common::thread_local::register_dtor_fallback;
|
||||
register_dtor_fallback(t, dtor);
|
||||
}
|
||||
|
||||
pub fn requires_move_before_drop() -> bool {
|
||||
false
|
||||
}
|
|
@ -36,8 +36,6 @@ pub mod net;
|
|||
pub mod os;
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
pub mod ext;
|
||||
#[path = "../wasm/fast_thread_local.rs"]
|
||||
pub mod fast_thread_local;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
pub mod process;
|
||||
|
@ -47,8 +45,10 @@ pub mod rwlock;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
#[path = "../wasm/thread_local.rs"]
|
||||
pub mod thread_local;
|
||||
#[path = "../wasm/thread_local_dtor.rs"]
|
||||
pub mod thread_local_dtor;
|
||||
#[path = "../wasm/thread_local_key.rs"]
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
#[cfg(not(test))]
|
||||
|
|
|
@ -20,7 +20,6 @@ pub mod alloc;
|
|||
pub mod args;
|
||||
pub mod cmath;
|
||||
pub mod env;
|
||||
pub mod fast_thread_local;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
pub mod memchr;
|
||||
|
@ -32,7 +31,8 @@ pub mod process;
|
|||
pub mod stack_overflow;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
pub use crate::sys_common::os_str_bytes as os_str;
|
||||
|
|
|
@ -20,7 +20,6 @@ pub mod cmath;
|
|||
pub mod condvar;
|
||||
pub mod env;
|
||||
pub mod ext;
|
||||
pub mod fast_thread_local;
|
||||
pub mod fs;
|
||||
pub mod handle;
|
||||
pub mod io;
|
||||
|
@ -35,7 +34,8 @@ pub mod process;
|
|||
pub mod rand;
|
||||
pub mod rwlock;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_vendor = "uwp"))] {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![unstable(feature = "thread_local_internals", issue = "none")]
|
||||
#![cfg(target_thread_local)]
|
||||
|
||||
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
|
||||
pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
|
|
@ -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;
|
||||
|
||||
|
|
49
src/libstd/sys_common/thread_local_dtor.rs
Normal file
49
src/libstd/sys_common/thread_local_dtor.rs
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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};
|
|
@ -363,7 +363,7 @@ pub mod fast {
|
|||
use crate::cell::Cell;
|
||||
use crate::fmt;
|
||||
use crate::mem;
|
||||
use crate::sys::fast_thread_local::register_dtor;
|
||||
use crate::sys::thread_local_dtor::register_dtor;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum DtorState {
|
||||
|
@ -468,7 +468,7 @@ pub mod os {
|
|||
use crate::fmt;
|
||||
use crate::marker;
|
||||
use crate::ptr;
|
||||
use crate::sys_common::thread_local::StaticKey as OsStaticKey;
|
||||
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
|
||||
|
||||
pub struct Key<T> {
|
||||
// OS-TLS key that we'll use to key off.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue