Skip to content

Improve TLS codegen by marking the panic/init path as cold #143511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/std/src/sys/thread_local/key/racy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ impl LazyKey {
}
}

#[cold]
fn lazy_init(&self) -> usize {
// POSIX allows the key created here to be KEY_SENTVAL, but the compare_exchange
// below relies on using KEY_SENTVAL as a sentinel value to check who won the
Expand Down
12 changes: 9 additions & 3 deletions library/std/src/sys/thread_local/key/xous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ unsafe extern "Rust" {
static DTORS: Atomic<*mut Node>;
}

#[inline]
fn tls_ptr_addr() -> *mut *mut u8 {
let mut tp: usize;
unsafe {
Expand All @@ -80,14 +81,19 @@ fn tls_ptr_addr() -> *mut *mut u8 {

/// Creates an area of memory that's unique per thread. This area will
/// contain all thread local pointers.
#[inline]
fn tls_table() -> &'static mut [*mut u8] {
let tp = tls_ptr_addr();

if !tp.is_null() {
return unsafe {
core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::<*mut u8>())
};
unsafe { core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::<*mut u8>()) }
} else {
tls_table_slow()
}
}

#[cold]
fn tls_table_slow() -> &'static mut [*mut u8] {
// If the TP register is `0`, then this thread hasn't initialized
// its TLS yet. Allocate a new page to store this memory.
let tp = unsafe {
Expand Down
22 changes: 14 additions & 8 deletions library/std/src/sys/thread_local/native/eager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::sys::thread_local::{abort_on_dtor_unwind, destructors};

#[derive(Clone, Copy)]
enum State {
Initial,
Uninitialized,
Alive,
Destroyed,
}
Expand All @@ -17,7 +17,7 @@ pub struct Storage<T> {

impl<T> Storage<T> {
pub const fn new(val: T) -> Storage<T> {
Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) }
Storage { state: Cell::new(State::Uninitialized), val: UnsafeCell::new(val) }
}

/// Gets a pointer to the TLS value. If the TLS variable has been destroyed,
Expand All @@ -30,16 +30,22 @@ impl<T> Storage<T> {
/// The `self` reference must remain valid until the TLS destructor is run.
#[inline]
pub unsafe fn get(&self) -> *const T {
match self.state.get() {
State::Alive => self.val.get(),
State::Destroyed => ptr::null(),
State::Initial => unsafe { self.initialize() },
if let State::Alive = self.state.get() {
self.val.get()
} else {
unsafe { self.get_or_init_slow() }
}
}

#[cold]
unsafe fn initialize(&self) -> *const T {
// Register the destructor
unsafe fn get_or_init_slow(&self) -> *const T {
match self.state.get() {
State::Uninitialized => {}
State::Alive => return self.val.get(),
State::Destroyed => return ptr::null(),
}

// Register the destructor.

// SAFETY:
// The caller guarantees that `self` will be valid until thread destruction.
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/thread_local/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl<T: 'static> Storage<T> {
///
/// The resulting pointer may not be used after reentrant inialialization
/// or thread destruction has occurred.
#[inline]
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
let key = self.key.force();
let ptr = unsafe { get(key) as *mut Value<T> };
Expand All @@ -84,6 +85,7 @@ impl<T: 'static> Storage<T> {
/// # Safety
/// * `key` must be the result of calling `self.key.force()`
/// * `ptr` must be the current value associated with `key`.
#[cold]
unsafe fn try_initialize(
key: Key,
ptr: *mut Value<T>,
Expand Down
Loading