mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Make sentinel value configurable
There are OSs that always return the lowest free value. The algorithm in `lazy_init` always avoids keys with the sentinel value. In affected OSs, this means that each call to `lazy_init` will always request two keys from the OS and returns/frees the first one (with sentinel value) immediately afterwards. By making the sentinel value configurable, affected OSs can use a different value than zero to prevent this performance issue.
This commit is contained in:
parent
ed61c139c2
commit
980065ab23
@ -117,10 +117,14 @@ pub struct Key {
|
||||
/// This value specifies no destructor by default.
|
||||
pub const INIT: StaticKey = StaticKey::new(None);
|
||||
|
||||
// Define a sentinel value that is unlikely to be returned
|
||||
// as a TLS key (but it may be returned).
|
||||
const KEY_SENTVAL: usize = 0;
|
||||
|
||||
impl StaticKey {
|
||||
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
|
||||
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
|
||||
StaticKey { key: atomic::AtomicUsize::new(0), dtor }
|
||||
StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
|
||||
}
|
||||
|
||||
/// Gets the value associated with this TLS key
|
||||
@ -144,31 +148,36 @@ impl StaticKey {
|
||||
#[inline]
|
||||
unsafe fn key(&self) -> imp::Key {
|
||||
match self.key.load(Ordering::Relaxed) {
|
||||
0 => self.lazy_init() as imp::Key,
|
||||
KEY_SENTVAL => self.lazy_init() as imp::Key,
|
||||
n => n as imp::Key,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn lazy_init(&self) -> usize {
|
||||
// POSIX allows the key created here to be 0, but the compare_exchange
|
||||
// below relies on using 0 as a sentinel value to check who won the
|
||||
// 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
|
||||
// race to set the shared TLS key. As far as I know, there is no
|
||||
// guaranteed value that cannot be returned as a posix_key_create key,
|
||||
// so there is no value we can initialize the inner key with to
|
||||
// prove that it has not yet been set. As such, we'll continue using a
|
||||
// value of 0, but with some gyrations to make sure we have a non-0
|
||||
// value of KEY_SENTVAL, but with some gyrations to make sure we have a non-KEY_SENTVAL
|
||||
// value returned from the creation routine.
|
||||
// FIXME: this is clearly a hack, and should be cleaned up.
|
||||
let key1 = imp::create(self.dtor);
|
||||
let key = if key1 != 0 {
|
||||
let key = if key1 as usize != KEY_SENTVAL {
|
||||
key1
|
||||
} else {
|
||||
let key2 = imp::create(self.dtor);
|
||||
imp::destroy(key1);
|
||||
key2
|
||||
};
|
||||
rtassert!(key != 0);
|
||||
match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
|
||||
rtassert!(key as usize != KEY_SENTVAL);
|
||||
match self.key.compare_exchange(
|
||||
KEY_SENTVAL,
|
||||
key as usize,
|
||||
Ordering::SeqCst,
|
||||
Ordering::SeqCst,
|
||||
) {
|
||||
// The CAS succeeded, so we've created the actual key
|
||||
Ok(_) => key as usize,
|
||||
// If someone beat us to the punch, use their key instead
|
||||
|
Loading…
Reference in New Issue
Block a user