Upgrade thread_local to 1.1.7 am: 4039605b26

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/thread_local/+/2442943

Change-Id: I5bc12c4bf8e4871f7eb877e216740ef88cfcaa69
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index f17b5e4..98f2b9b 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "4a54e5702e0968bdda77366738ba646f646044e8"
+    "sha1": "d9c6ff3e751408c3f2e58b15dcc047e3669b9292"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..1d0e51b
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,16 @@
+on: [push, pull_request]
+
+name: Continuous integration
+
+jobs:
+  test:
+    name: Test
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@1.59.0
+        with:
+          components: rustfmt
+      - run: cargo fmt -- --check
+      - run: cargo test
+      - run: cargo bench
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 16bf2d2..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-language: rust
-sudo: false
-
-rust:
-- nightly
-- beta
-- stable
-- 1.36.0
-
-before_script:
-- |
-  pip install 'travis-cargo<0.2' --user &&
-  export PATH=$HOME/.local/bin:$PATH
-
-script:
-- travis-cargo build
-- travis-cargo test
-- travis-cargo bench -- --features criterion
-# Criterion may drop support for 1.36.0 in the future. If it does, replace the above line with this:
-# - travis-cargo --skip 1.36.0 bench -- --features criterion
-- travis-cargo doc -- --no-deps
-
-after_success:
-- travis-cargo --only nightly doc-upload
-env:
-  global:
-  - TRAVIS_CARGO_NIGHTLY_FEATURE=""
-
-notifications:
-  email: false
diff --git a/Android.bp b/Android.bp
index 223fd47..d6736e4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,12 +42,17 @@
     host_supported: true,
     crate_name: "thread_local",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.1.4",
+    cargo_pkg_version: "1.1.7",
     srcs: ["src/lib.rs"],
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
+        "libcfg_if",
         "libonce_cell",
     ],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
 }
 
 rust_test {
@@ -55,15 +60,17 @@
     host_supported: true,
     crate_name: "thread_local",
     cargo_env_compat: true,
-    cargo_pkg_version: "1.1.4",
+    cargo_pkg_version: "1.1.7",
     srcs: ["src/lib.rs"],
     test_suites: ["general-tests"],
     auto_gen_config: true,
     test_options: {
         unit_test: true,
     },
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
+        "libcfg_if",
+        "libcriterion",
         "libonce_cell",
     ],
 }
diff --git a/Cargo.toml b/Cargo.toml
index 90e5319..d773a90 100644
--- a/Cargo.toml
+++ b/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/Cargo.toml.orig b/Cargo.toml.orig
index f2e8ff0..56d301c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,27 +1,30 @@
 [package]
 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/"
-license = "Apache-2.0/MIT"
+license = "MIT OR Apache-2.0"
 repository = "https://github.com/Amanieu/thread_local-rs"
 readme = "README.md"
 keywords = ["thread_local", "concurrent", "thread"]
-edition = "2018"
+edition = "2021"
+
+[features]
+# this feature provides performance improvements using nightly features
+nightly = []
 
 [badges]
 travis-ci = { repository = "Amanieu/thread_local-rs" }
 
 [dependencies]
 once_cell = "1.5.2"
-
-# This is actually a dev-dependency, see https://github.com/rust-lang/cargo/issues/1596
-criterion = { version = "0.3.3", optional = true }
+# this is required to gate `nightly` related code paths
+cfg-if = "1.0.0"
 
 [dev-dependencies]
+criterion = "0.4.0"
 
 [[bench]]
 name = "thread_local"
-required-features = ["criterion"]
 harness = false
diff --git a/METADATA b/METADATA
index 4c77c6a..0466287 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/thread_local
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "thread_local"
 description: "Per-object thread-local storage"
 third_party {
@@ -7,13 +11,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/thread_local/thread_local-1.1.4.crate"
+    value: "https://static.crates.io/crates/thread_local/thread_local-1.1.7.crate"
   }
-  version: "1.1.4"
+  version: "1.1.7"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2022
-    month: 3
-    day: 1
+    year: 2023
+    month: 2
+    day: 17
   }
 }
diff --git a/README.md b/README.md
index 6560356..914451c 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
 
 ## 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/benches/thread_local.rs b/benches/thread_local.rs
index ccad665..dd4716d 100644
--- a/benches/thread_local.rs
+++ b/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/src/lib.rs b/src/lib.rs
index 33b79d6..12d25f6 100644
--- a/src/lib.rs
+++ b/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::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 @@
     /// 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 @@
                 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 @@
             // 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 @@
         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 @@
     }
 
     #[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 @@
     ) 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/src/thread_id.rs b/src/thread_id.rs
index 6eb0f61..aa4f2d6 100644
--- a/src/thread_id.rs
+++ b/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 @@
     }
 }
 
-/// 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) } }; }
 
-thread_local!(static THREAD_HOLDER: ThreadHolder = ThreadHolder::new());
+        // 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>,
+        }
 
-/// Get the current thread.
-pub(crate) fn get() -> Thread {
-    THREAD_HOLDER.with(|holder| holder.0)
+        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());
+            }
+        }
+
+        /// 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]