Skip to content

Commit 430a091

Browse files
committed
ensure fast thread local lookups occur once per access on macos
1 parent ae4be16 commit 430a091

File tree

4 files changed

+32
-6
lines changed

4 files changed

+32
-6
lines changed
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
#![cfg(target_thread_local)]
22
#![unstable(feature = "thread_local_internals", issue = "0")]
33

4-
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
4+
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
5+
6+
pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
7+
*ptr
8+
}

src/libstd/sys/unix/fast_thread_local.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,20 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
8282
}
8383
}
8484
}
85+
86+
#[cfg(not(target_os = "macos"))]
87+
pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
88+
*ptr
89+
}
90+
91+
#[cfg(target_os = "macos")]
92+
pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
93+
// On macos, thread_local lookups can result in terrible code due to
94+
// aggressive rerunning of the macos equivalent of `__tls_get_addr` - four
95+
// lookups per actual reference in user code.
96+
//
97+
// Using a read_volatile on a value holding fast Key's address tricks the
98+
// optimizer into only calling the macos get_addr equivalent once per time
99+
// requested by the user.
100+
crate::ptr::read_volatile(ptr)
101+
}

src/libstd/sys/windows/fast_thread_local.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22
#![cfg(target_thread_local)]
33

44
pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
5+
6+
pub unsafe fn lookup_once<T>(ptr: *const &T) -> &T {
7+
*ptr
8+
}

src/libstd/thread/local.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ pub mod fast {
344344
use crate::fmt;
345345
use crate::mem;
346346
use crate::ptr;
347-
use crate::sys::fast_thread_local::register_dtor;
347+
use crate::sys::fast_thread_local::{lookup_once, register_dtor};
348348

349349
pub struct Key<T> {
350350
inner: UnsafeCell<Option<T>>,
@@ -371,11 +371,12 @@ pub mod fast {
371371
}
372372

373373
pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
374-
if mem::needs_drop::<T>() && self.dtor_running.get() {
374+
let this = lookup_once(&self);
375+
if mem::needs_drop::<T>() && this.dtor_running.get() {
375376
return None
376377
}
377-
self.register_dtor();
378-
Some(&*(&self.inner as *const _))
378+
this.register_dtor();
379+
Some(&*(&this.inner as *const _))
379380
}
380381

381382
unsafe fn register_dtor(&self) {
@@ -395,7 +396,7 @@ pub mod fast {
395396
// destructor as running for this thread so calls to `get` will return
396397
// `None`.
397398
(*ptr).dtor_running.set(true);
398-
399+
399400
ptr::drop_in_place((*ptr).inner.get());
400401
}
401402
}

0 commit comments

Comments
 (0)