about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-12-28 22:22:18 +0100
committerGitHub <noreply@github.com>2022-12-28 22:22:18 +0100
commit22060f20ae0b92acd056c4f2c79d19dd1b73ab5c (patch)
tree6ad221e04ee4387e35c3fb2ebf087ceb9c59838c /library
parent2dd2fb728e61a6e7912e1e2818407625ad806bb9 (diff)
parent980065ab23650452c33bb47ef66d75fbfbcb6e04 (diff)
downloadrust-22060f20ae0b92acd056c4f2c79d19dd1b73ab5c.tar.gz
rust-22060f20ae0b92acd056c4f2c79d19dd1b73ab5c.zip
Rollup merge of #105359 - flba-eb:thread_local_key_sentinel_value, r=m-ou-se
Make sentinel value configurable in `library/std/src/sys_common/thread_local_key.rs`

This is an excerpt of a changeset for the QNX/Neutrino OS. To make the patch for QNX smaller and easier to review, I've extracted this change (which is OS independent). I would be surprised if no other OS is also affected.

All this patch does is to define a `const` for a sentinel value instead of using it directly at several places.

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.

On QNX/Neutrino, it is planned to use a different sentinel value:
```rust
// Define a sentinel value that is unlikely to be returned
// as a TLS key (but it may be returned).
#[cfg(not(target_os = "nto"))]
const KEY_SENTVAL: usize = 0;
// On QNX/Neutrino, 0 is always returned when currently not in use.
// Using 0 would mean to always create two keys and remote the first
// one (with value of 0) immediately afterwards.
#[cfg(target_os = "nto")]
const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
```

It seems like no other OS defines `PTHREAD_KEYS_MAX` in Rusts libc, but `limits.h` on unix systems does.
Diffstat (limited to 'library')
-rw-r--r--library/std/src/sys_common/thread_local_key.rs25
1 files changed, 17 insertions, 8 deletions
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 747579f1781..2672a2a75b0 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -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