diff --git a/library/std/src/sys/unix/thread_local_key.rs b/library/std/src/sys/unix/thread_local_key.rs index 2c5b94b1e61e5..14f436e02aaf8 100644 --- a/library/std/src/sys/unix/thread_local_key.rs +++ b/library/std/src/sys/unix/thread_local_key.rs @@ -6,8 +6,23 @@ pub type Key = libc::pthread_key_t; #[inline] pub unsafe fn create(dtor: Option) -> Key { + let dtor = mem::transmute(dtor); let mut key = 0; - assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); + assert_eq!(libc::pthread_key_create(&mut key, dtor), 0); + // POSIX allows the key created here to be 0, but `StaticKey` needs to + // use 0 as a sentinel value to check who won the race to set the shared + // TLS key. Therefore, we employ this small trick to avoid having to waste + // the key value. + if key == 0 { + let mut new = 0; + // Only check the results after the old key has been destroyed to avoid + // leaking it. + let r_c = libc::pthread_key_create(&mut new, dtor); + let r_d = libc::pthread_key_delete(key); + assert_eq!(r_c, 0); + debug_assert_eq!(r_d, 0); + key = new; + } key } diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 032bf604d7388..8111baebd45f0 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -113,11 +113,6 @@ pub struct Key { key: imp::Key, } -/// Constant initialization value for static TLS keys. -/// -/// This value specifies no destructor by default. -pub const INIT: StaticKey = StaticKey::new(None); - impl StaticKey { #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new(dtor: Option) -> StaticKey { @@ -170,24 +165,9 @@ impl StaticKey { return key; } - // 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 - // 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 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 { - key1 - } else { - let key2 = imp::create(self.dtor); - imp::destroy(key1); - key2 - }; - rtassert!(key != 0); + let key = imp::create(self.dtor); + // Implementations have to ensure key values are not zero. + debug_assert_ne!(key, 0); match self.key.compare_exchange(0, key as usize, Ordering::SeqCst, Ordering::SeqCst) { // The CAS succeeded, so we've created the actual key Ok(_) => key as usize,