Skip to content

Commit 980065a

Browse files
committed
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.
1 parent ed61c13 commit 980065a

File tree

1 file changed

+17
-8
lines changed

1 file changed

+17
-8
lines changed

library/std/src/sys_common/thread_local_key.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,14 @@ pub struct Key {
117117
/// This value specifies no destructor by default.
118118
pub const INIT: StaticKey = StaticKey::new(None);
119119

120+
// Define a sentinel value that is unlikely to be returned
121+
// as a TLS key (but it may be returned).
122+
const KEY_SENTVAL: usize = 0;
123+
120124
impl StaticKey {
121125
#[rustc_const_unstable(feature = "thread_local_internals", issue = "none")]
122126
pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
123-
StaticKey { key: atomic::AtomicUsize::new(0), dtor }
127+
StaticKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
124128
}
125129

126130
/// Gets the value associated with this TLS key
@@ -144,31 +148,36 @@ impl StaticKey {
144148
#[inline]
145149
unsafe fn key(&self) -> imp::Key {
146150
match self.key.load(Ordering::Relaxed) {
147-
0 => self.lazy_init() as imp::Key,
151+
KEY_SENTVAL => self.lazy_init() as imp::Key,
148152
n => n as imp::Key,
149153
}
150154
}
151155

152156
unsafe fn lazy_init(&self) -> usize {
153-
// POSIX allows the key created here to be 0, but the compare_exchange
154-
// below relies on using 0 as a sentinel value to check who won the
157+
// POSIX allows the key created here to be KEY_SENTVAL, but the compare_exchange
158+
// below relies on using KEY_SENTVAL as a sentinel value to check who won the
155159
// race to set the shared TLS key. As far as I know, there is no
156160
// guaranteed value that cannot be returned as a posix_key_create key,
157161
// so there is no value we can initialize the inner key with to
158162
// prove that it has not yet been set. As such, we'll continue using a
159-
// value of 0, but with some gyrations to make sure we have a non-0
163+
// value of KEY_SENTVAL, but with some gyrations to make sure we have a non-KEY_SENTVAL
160164
// value returned from the creation routine.
161165
// FIXME: this is clearly a hack, and should be cleaned up.
162166
let key1 = imp::create(self.dtor);
163-
let key = if key1 != 0 {
167+
let key = if key1 as usize != KEY_SENTVAL {
164168
key1
165169
} else {
166170
let key2 = imp::create(self.dtor);
167171
imp::destroy(key1);
168172
key2
169173
};
170-
rtassert!(key != 0);
171-
match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) {
174+
rtassert!(key as usize != KEY_SENTVAL);
175+
match self.key.compare_exchange(
176+
KEY_SENTVAL,
177+
key as usize,
178+
Ordering::SeqCst,
179+
Ordering::SeqCst,
180+
) {
172181
// The CAS succeeded, so we've created the actual key
173182
Ok(_) => key as usize,
174183
// If someone beat us to the punch, use their key instead

0 commit comments

Comments
 (0)