-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
std: Add a variant of thread locals with const init #83416
Conversation
r? @sfackler (rust-highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
85ca7d3
to
ab4622f
Compare
// If the platform has support for `#[thread_local]`, use it. | ||
#[cfg(all( | ||
target_thread_local, | ||
not(all(target_arch = "wasm32", not(target_feature = "atomics"))), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does wasm32 declare support for target_thread_local?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, yes, beacuse it's supported with atomics enabled. Last I checked (a year or two ago) it just didn't behave well in LLVM if atomics was disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably best to file an issue tracking that.
@@ -442,6 +558,12 @@ pub mod fast { | |||
Key { inner: LazyKeyInner::new(), dtor_state: Cell::new(DtorState::Unregistered) } | |||
} | |||
|
|||
pub unsafe fn register_dtor(a: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { | |||
unsafe { | |||
register_dtor(a, dtor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this infinitely recursive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this is actually recursing into a free-function so this shouldn't be infinitely recursive. The only purpose of this is for the macro-generated code to have a public function to call into, but I can document this better too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah missed this was an associated function.
Is this intended for internal-only use, or do you see us stabilizing this at some point? It seems pretty unfortunate to have two macros like this in a stable public API. |
My intent would be to have this stabilized at some point. This gap in Rust's thread-local support has come up from time to time and I'd hope that this would get us much closer to closing the gap on performance. I agree though that the API isn't great. Ideally I'd like to do something like test whether the input expression to thread_local!(const FOO: u32 = 3);
thread_local!(static FOO: u32 = const 3); (etc) One part I wasn't sure about though is that if an alternative syntax is chosen I'm not sure how to make just the new syntax unstable while keeping the current syntax stable. |
Oops, missed that you replied! One option is the thread_local! {
static FOO: u32 = const { 3 };
} |
ab4622f
to
0b86126
Compare
Oh nice! I've updated to use that syntax (and also discovered a way to make only some arms of a macro unstable while the others are stable) |
0b86126
to
6555364
Compare
library/std/src/thread/local.rs
Outdated
unsafe { | ||
debug_assert_eq!(STATE, 1); | ||
STATE = 2; | ||
drop(ptr.read()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this could use drop_in_place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh this specifically avoids that since it's caused issues in the past with macOS and TLS I think, but I'll add some comments to this effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope turns out I was misremembering, updated to use drop_in_place
r=me with a tracking issue and that one nit addressed. |
6555364
to
82cef56
Compare
📌 Commit 82cef56b15139a03092ef5d6636dbfa3f7e722b4 has been approved by |
This comment has been minimized.
This comment has been minimized.
@bors: r- |
This commit adds a variant of the `thread_local!` macro as a new `thread_local_const_init!` macro which requires that the initialization expression is constant (e.g. could be stuck into a `const` if so desired). This form of thread local allows for a more efficient implementation of `LocalKey::with` both if the value has a destructor and if it doesn't. If the value doesn't have a destructor then `with` should desugar to exactly as-if you use `#[thread_local]` given sufficient inlining. The purpose of this new form of thread locals is to precisely be equivalent to `#[thread_local]` on platforms where possible for values which fit the bill (those without destructors). This should help close the gap in performance between `thread_local!`, which is safe, relative to `#[thread_local]`, which is not easy to use in a portable fashion.
@bors: r=sfackler |
📌 Commit 82cef56b15139a03092ef5d6636dbfa3f7e722b4 has been approved by |
@bors: r=sfackler |
📌 Commit c6eea22 has been approved by |
☀️ Test successful - checks-actions |
…=alexcrichton fix aliasing violations in thread_local_const_init Fixes rust-lang#83416 (comment) r? `@alexcrichton` `@sfackler`
.unwrap(); | ||
|
||
unsafe { | ||
HITS = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes that the TLS destructors have run by the time join()
returns. This is currently not the case for the x86_64-fortanix-unknown-sgx target.
I'm a bit torn on whether this is the bug in the x86_64-fortanix-unknown-sgx implementation or this assumption is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TLS destructors need to run on the thread that is in the process of exiting. I think join()
shouldn't return until thread is completely done exiting and thus would have finished running the TLS destructors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, having a thread do anything after join
returned is highly suspicious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #84409
…r=dtolnay Ensure TLS destructors run before thread joins in SGX The excellent test is from `@jethrogb` For context see: rust-lang#83416 (comment)
…r=dtolnay Ensure TLS destructors run before thread joins in SGX The excellent test is from ``@jethrogb`` For context see: rust-lang#83416 (comment)
…r=dtolnay Ensure TLS destructors run before thread joins in SGX The excellent test is from ```@jethrogb``` For context see: rust-lang#83416 (comment)
Oh wow, this is awesome, thanks alexcrichton! |
…r=dtolnay Ensure TLS destructors run before thread joins in SGX The excellent test is from `@jethrogb` For context see: rust-lang#83416 (comment)
…r=dtolnay Ensure TLS destructors run before thread joins in SGX The excellent test is from ``@jethrogb`` For context see: rust-lang#83416 (comment)
…r=jethrogb Ensure TLS destructors run before thread joins in SGX The excellent test is from `@jethrogb` For context see: rust-lang#83416 (comment)
…r=jethrogb Ensure TLS destructors run before thread joins in SGX The excellent test is from ``@jethrogb`` For context see: rust-lang#83416 (comment)
…r=jethrogb Ensure TLS destructors run before thread joins in SGX The excellent test is from ```@jethrogb``` For context see: rust-lang#83416 (comment)
// just get going. | ||
if !$crate::mem::needs_drop::<$t>() { | ||
#[thread_local] | ||
static mut VAL: $t = $init; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mut
here seems unnecessary.
…d, r=thomcc Document `const {}` syntax for `std::thread_local`. It exists and is pretty cool. More people should use it. It was added in rust-lang#83416 and stabilized in rust-lang#91355 with the tracking issue rust-lang#84223.
This commit adds a variant of the
thread_local!
macro as a newthread_local_const_init!
macro which requires that the initializationexpression is constant (e.g. could be stuck into a
const
if sodesired). This form of thread local allows for a more efficient
implementation of
LocalKey::with
both if the value has a destructorand if it doesn't. If the value doesn't have a destructor then
with
should desugar to exactly as-if you use
#[thread_local]
givensufficient inlining.
The purpose of this new form of thread locals is to precisely be
equivalent to
#[thread_local]
on platforms where possible for valueswhich fit the bill (those without destructors). This should help close
the gap in performance between
thread_local!
, which is safe, relativeto
#[thread_local]
, which is not easy to use in a portable fashion.