summaryrefslogtreecommitdiffstats
path: root/vendor/thread_local
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/thread_local')
-rw-r--r--vendor/thread_local/.cargo-checksum.json2
-rw-r--r--vendor/thread_local/Cargo.toml26
-rw-r--r--vendor/thread_local/README.md2
-rw-r--r--vendor/thread_local/benches/thread_local.rs3
-rw-r--r--vendor/thread_local/src/lib.rs56
-rw-r--r--vendor/thread_local/src/thread_id.rs112
6 files changed, 147 insertions, 54 deletions
diff --git a/vendor/thread_local/.cargo-checksum.json b/vendor/thread_local/.cargo-checksum.json
index f9cb3e1bd..b02a9490a 100644
--- a/vendor/thread_local/.cargo-checksum.json
+++ b/vendor/thread_local/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"db2c006192c59fb9465a813ff0a8012fae8ca13e839a1ff92b0c7ef3ecfbe032","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"44a77143b8ea0cba5a64873fa77c76aad209d8d80068b2bd11986dadb9f97ed7","benches/thread_local.rs":"29f8fbc4fc7cf0b93b02bbf20e73113cbde2388d962cd5c617918f900a6893ec","src/cached.rs":"253cb48da470265f4c4702a4f9f6b8670860cb092d8304d807717d751d0b3350","src/lib.rs":"92ae38e941e1b4c0f32e1f415e272f76374cb6f5aa8752275202fa856d3876e9","src/thread_id.rs":"53ae035d18d31eae822c9ff82219da34deed1234686d6fe3a82ca5da51ffd6a1","src/unreachable.rs":"f0c65f1b0516cc92fbd7df2c8c8edfdac5362377d27ae5b91a12204673e2fd73"},"package":"5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"} \ No newline at end of file
+{"files":{"Cargo.toml":"1c3ffde735d10adc9bc72b296db6fd448581eddedb494f64cd966ce3de8d4b13","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"d33aea1cf2bbc915e89347975fae37cc3d51df0227d56d070d8adc534200fca4","benches/thread_local.rs":"37dc7f2b6bc30ea093828ae0e5509dc5ffdf63fa8127804ff359e49e1175356e","src/cached.rs":"253cb48da470265f4c4702a4f9f6b8670860cb092d8304d807717d751d0b3350","src/lib.rs":"d65f31267980b0035aec8c7d503f0fef0d8615a0eb8311f2b3887e038d178153","src/thread_id.rs":"ab6dd1278798cb5d7c49a60a2e642fc0e0462e316938c8097757f5a5b9579b38","src/unreachable.rs":"f0c65f1b0516cc92fbd7df2c8c8edfdac5362377d27ae5b91a12204673e2fd73"},"package":"3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"} \ No newline at end of file
diff --git a/vendor/thread_local/Cargo.toml b/vendor/thread_local/Cargo.toml
index 90e53190d..d773a9015 100644
--- a/vendor/thread_local/Cargo.toml
+++ b/vendor/thread_local/Cargo.toml
@@ -10,28 +10,36 @@
# See Cargo.toml.orig for the original contents.
[package]
-edition = "2018"
+edition = "2021"
name = "thread_local"
-version = "1.1.4"
+version = "1.1.7"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
description = "Per-object thread-local storage"
documentation = "https://docs.rs/thread_local/"
readme = "README.md"
-keywords = ["thread_local", "concurrent", "thread"]
-license = "Apache-2.0/MIT"
+keywords = [
+ "thread_local",
+ "concurrent",
+ "thread",
+]
+license = "MIT OR Apache-2.0"
repository = "https://github.com/Amanieu/thread_local-rs"
[[bench]]
name = "thread_local"
harness = false
-required-features = ["criterion"]
-[dependencies.criterion]
-version = "0.3.3"
-optional = true
+
+[dependencies.cfg-if]
+version = "1.0.0"
[dependencies.once_cell]
version = "1.5.2"
-[dev-dependencies]
+[dev-dependencies.criterion]
+version = "0.4.0"
+
+[features]
+nightly = []
+
[badges.travis-ci]
repository = "Amanieu/thread_local-rs"
diff --git a/vendor/thread_local/README.md b/vendor/thread_local/README.md
index 6560356f2..914451c11 100644
--- a/vendor/thread_local/README.md
+++ b/vendor/thread_local/README.md
@@ -21,7 +21,7 @@ thread_local = "1.1"
## Minimum Rust version
-This crate's minimum supported Rust version (MSRV) is 1.36.0.
+This crate's minimum supported Rust version (MSRV) is 1.59.0.
## License
diff --git a/vendor/thread_local/benches/thread_local.rs b/vendor/thread_local/benches/thread_local.rs
index ccad6655e..dd4716d87 100644
--- a/vendor/thread_local/benches/thread_local.rs
+++ b/vendor/thread_local/benches/thread_local.rs
@@ -1,6 +1,3 @@
-extern crate criterion;
-extern crate thread_local;
-
use criterion::{black_box, BatchSize};
use thread_local::ThreadLocal;
diff --git a/vendor/thread_local/src/lib.rs b/vendor/thread_local/src/lib.rs
index 33b79d6a5..12d25f6c3 100644
--- a/vendor/thread_local/src/lib.rs
+++ b/vendor/thread_local/src/lib.rs
@@ -65,6 +65,7 @@
#![warn(missing_docs)]
#![allow(clippy::mutex_atomic)]
+#![cfg_attr(feature = "nightly", feature(thread_local))]
mod cached;
mod thread_id;
@@ -81,7 +82,6 @@ use std::mem::MaybeUninit;
use std::panic::UnwindSafe;
use std::ptr;
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
-use std::sync::Mutex;
use thread_id::Thread;
use unreachable::UncheckedResultExt;
@@ -107,11 +107,6 @@ pub struct ThreadLocal<T: Send> {
/// The number of values in the thread local. This can be less than the real number of values,
/// but is never more.
values: AtomicUsize,
-
- /// Lock used to guard against concurrent modifications. This is taken when
- /// there is a possibility of allocating a new bucket, which only occurs
- /// when inserting values.
- lock: Mutex<()>,
}
struct Entry<T> {
@@ -155,7 +150,7 @@ impl<T: Send> Drop for ThreadLocal<T> {
continue;
}
- unsafe { Box::from_raw(std::slice::from_raw_parts_mut(bucket_ptr, this_bucket_size)) };
+ unsafe { deallocate_bucket(bucket_ptr, this_bucket_size) };
}
}
}
@@ -190,14 +185,12 @@ impl<T: Send> ThreadLocal<T> {
// representation as a sequence of their inner type.
buckets: unsafe { mem::transmute(buckets) },
values: AtomicUsize::new(0),
- lock: Mutex::new(()),
}
}
/// Returns the element for the current thread, if it exists.
pub fn get(&self) -> Option<&T> {
- let thread = thread_id::get();
- self.get_inner(thread)
+ self.get_inner(thread_id::get())
}
/// Returns the element for the current thread, or creates it if it doesn't
@@ -220,10 +213,11 @@ impl<T: Send> ThreadLocal<T> {
F: FnOnce() -> Result<T, E>,
{
let thread = thread_id::get();
- match self.get_inner(thread) {
- Some(x) => Ok(x),
- None => Ok(self.insert(thread, create()?)),
+ if let Some(val) = self.get_inner(thread) {
+ return Ok(val);
}
+
+ Ok(self.insert(create()?))
}
fn get_inner(&self, thread: Thread) -> Option<&T> {
@@ -244,24 +238,34 @@ impl<T: Send> ThreadLocal<T> {
}
#[cold]
- fn insert(&self, thread: Thread, data: T) -> &T {
- // Lock the Mutex to ensure only a single thread is allocating buckets at once
- let _guard = self.lock.lock().unwrap();
-
+ fn insert(&self, data: T) -> &T {
+ let thread = thread_id::get();
let bucket_atomic_ptr = unsafe { self.buckets.get_unchecked(thread.bucket) };
-
let bucket_ptr: *const _ = bucket_atomic_ptr.load(Ordering::Acquire);
+
+ // If the bucket doesn't already exist, we need to allocate it
let bucket_ptr = if bucket_ptr.is_null() {
- // Allocate a new bucket
- let bucket_ptr = allocate_bucket(thread.bucket_size);
- bucket_atomic_ptr.store(bucket_ptr, Ordering::Release);
- bucket_ptr
+ let new_bucket = allocate_bucket(thread.bucket_size);
+
+ match bucket_atomic_ptr.compare_exchange(
+ ptr::null_mut(),
+ new_bucket,
+ Ordering::AcqRel,
+ Ordering::Acquire,
+ ) {
+ Ok(_) => new_bucket,
+ // If the bucket value changed (from null), that means
+ // another thread stored a new bucket before we could,
+ // and we can free our bucket and use that one instead
+ Err(bucket_ptr) => {
+ unsafe { deallocate_bucket(new_bucket, thread.bucket_size) }
+ bucket_ptr
+ }
+ }
} else {
bucket_ptr
};
- drop(_guard);
-
// Insert the new element into the bucket
let entry = unsafe { &*bucket_ptr.add(thread.index) };
let value_ptr = entry.value.get();
@@ -525,6 +529,10 @@ fn allocate_bucket<T>(size: usize) -> *mut Entry<T> {
) as *mut _
}
+unsafe fn deallocate_bucket<T>(bucket: *mut Entry<T>, size: usize) {
+ let _ = Box::from_raw(std::slice::from_raw_parts_mut(bucket, size));
+}
+
#[cfg(test)]
mod tests {
use super::ThreadLocal;
diff --git a/vendor/thread_local/src/thread_id.rs b/vendor/thread_local/src/thread_id.rs
index 6eb0f616f..aa4f2d632 100644
--- a/vendor/thread_local/src/thread_id.rs
+++ b/vendor/thread_local/src/thread_id.rs
@@ -7,6 +7,7 @@
use crate::POINTER_WIDTH;
use once_cell::sync::Lazy;
+use std::cell::Cell;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::sync::Mutex;
@@ -73,24 +74,103 @@ impl Thread {
}
}
-/// Wrapper around `Thread` that allocates and deallocates the ID.
-struct ThreadHolder(Thread);
-impl ThreadHolder {
- fn new() -> ThreadHolder {
- ThreadHolder(Thread::new(THREAD_ID_MANAGER.lock().unwrap().alloc()))
- }
-}
-impl Drop for ThreadHolder {
- fn drop(&mut self) {
- THREAD_ID_MANAGER.lock().unwrap().free(self.0.id);
- }
-}
+cfg_if::cfg_if! {
+ if #[cfg(feature = "nightly")] {
+ // This is split into 2 thread-local variables so that we can check whether the
+ // thread is initialized without having to register a thread-local destructor.
+ //
+ // This makes the fast path smaller.
+ #[thread_local]
+ static mut THREAD: Option<Thread> = None;
+ thread_local! { static THREAD_GUARD: ThreadGuard = const { ThreadGuard { id: Cell::new(0) } }; }
+
+ // Guard to ensure the thread ID is released on thread exit.
+ struct ThreadGuard {
+ // We keep a copy of the thread ID in the ThreadGuard: we can't
+ // reliably access THREAD in our Drop impl due to the unpredictable
+ // order of TLS destructors.
+ id: Cell<usize>,
+ }
-thread_local!(static THREAD_HOLDER: ThreadHolder = ThreadHolder::new());
+ impl Drop for ThreadGuard {
+ fn drop(&mut self) {
+ // Release the thread ID. Any further accesses to the thread ID
+ // will go through get_slow which will either panic or
+ // initialize a new ThreadGuard.
+ unsafe {
+ THREAD = None;
+ }
+ THREAD_ID_MANAGER.lock().unwrap().free(self.id.get());
+ }
+ }
-/// Get the current thread.
-pub(crate) fn get() -> Thread {
- THREAD_HOLDER.with(|holder| holder.0)
+ /// Returns a thread ID for the current thread, allocating one if needed.
+ #[inline]
+ pub(crate) fn get() -> Thread {
+ if let Some(thread) = unsafe { THREAD } {
+ thread
+ } else {
+ get_slow()
+ }
+ }
+
+ /// Out-of-line slow path for allocating a thread ID.
+ #[cold]
+ fn get_slow() -> Thread {
+ let new = Thread::new(THREAD_ID_MANAGER.lock().unwrap().alloc());
+ unsafe {
+ THREAD = Some(new);
+ }
+ THREAD_GUARD.with(|guard| guard.id.set(new.id));
+ new
+ }
+ } else {
+ // This is split into 2 thread-local variables so that we can check whether the
+ // thread is initialized without having to register a thread-local destructor.
+ //
+ // This makes the fast path smaller.
+ thread_local! { static THREAD: Cell<Option<Thread>> = const { Cell::new(None) }; }
+ thread_local! { static THREAD_GUARD: ThreadGuard = const { ThreadGuard { id: Cell::new(0) } }; }
+
+ // Guard to ensure the thread ID is released on thread exit.
+ struct ThreadGuard {
+ // We keep a copy of the thread ID in the ThreadGuard: we can't
+ // reliably access THREAD in our Drop impl due to the unpredictable
+ // order of TLS destructors.
+ id: Cell<usize>,
+ }
+
+ impl Drop for ThreadGuard {
+ fn drop(&mut self) {
+ // Release the thread ID. Any further accesses to the thread ID
+ // will go through get_slow which will either panic or
+ // initialize a new ThreadGuard.
+ let _ = THREAD.try_with(|thread| thread.set(None));
+ THREAD_ID_MANAGER.lock().unwrap().free(self.id.get());
+ }
+ }
+
+ /// Returns a thread ID for the current thread, allocating one if needed.
+ #[inline]
+ pub(crate) fn get() -> Thread {
+ THREAD.with(|thread| {
+ if let Some(thread) = thread.get() {
+ thread
+ } else {
+ get_slow(thread)
+ }
+ })
+ }
+
+ /// Out-of-line slow path for allocating a thread ID.
+ #[cold]
+ fn get_slow(thread: &Cell<Option<Thread>>) -> Thread {
+ let new = Thread::new(THREAD_ID_MANAGER.lock().unwrap().alloc());
+ thread.set(Some(new));
+ THREAD_GUARD.with(|guard| guard.id.set(new.id));
+ new
+ }
+ }
}
#[test]