Snap for 8270536 from bb8a50689a4fcfef776159065580bd8d7e28c7be to tm-release

Change-Id: I1727a255c22a13136777aff29cd61ce2934140e6
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 58935f2..38c6551 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
 {
   "git": {
-    "sha1": "18001b819c1539c06c176c671bbe54e70b5c3d69"
-  }
-}
+    "sha1": "a75875b0bf904287a9749e8eabea919b5e9dd8a9"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index 39c8d2d..4d33593 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -2,11 +2,11 @@
 
 on:
   push:
-    branches-ignore:
-      - trying.tmp
-      - staging.tmp
+    branches:
+      - trying
+      - staging
   pull_request:
-    
+
 env:
   RUST_TEST_THREADS: 1
 
@@ -25,6 +25,9 @@
           - channel: nightly
             feature: nightly
             os: ubuntu
+          - channel: nightly
+            feature: hardware-lock-elision
+            os: ubuntu
 
     steps:
     - uses: actions/checkout@v2
diff --git a/Android.bp b/Android.bp
index 90bc2cb..17f0e2b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,12 +42,11 @@
     host_supported: true,
     crate_name: "parking_lot",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.11.2",
+    cargo_pkg_version: "0.12.0",
     srcs: ["src/lib.rs"],
     edition: "2018",
     features: ["default"],
     rustlibs: [
-        "libinstant",
         "liblock_api",
         "libparking_lot_core",
     ],
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5cd4e6b..d1951e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## parking_lot 0.12.0, parking_lot_core 0.9.0, lock_api 0.4.6 (2022-01-28)
+
+- The MSRV is bumped to 1.49.0.
+- Disabled eventual fairness on wasm32-unknown-unknown. (#302)
+- Added a rwlock method to report if lock is held exclusively. (#303)
+- Use new `asm!` macro. (#304)
+- Use windows-rs instead of winapi for faster builds. (#311)
+- Moved hardware lock elision support to a separate Cargo feature. (#313)
+- Removed used of deprecated `spin_loop_hint`. (#314)
+
 ## parking_lot 0.11.2, parking_lot_core 0.8.4, lock_api 0.4.5 (2021-08-28)
 
 - Fixed incorrect memory orderings on `RwLock` and `WordLock`. (#294, #292)
diff --git a/Cargo.toml b/Cargo.toml
index 549151b..6f58afa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,7 +12,7 @@
 [package]
 edition = "2018"
 name = "parking_lot"
-version = "0.11.2"
+version = "0.12.0"
 authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
 description = "More compact and efficient implementations of the standard synchronization primitives."
 readme = "README.md"
@@ -20,14 +20,11 @@
 categories = ["concurrency"]
 license = "Apache-2.0/MIT"
 repository = "https://github.com/Amanieu/parking_lot"
-[dependencies.instant]
-version = "0.1.9"
-
 [dependencies.lock_api]
-version = "0.4.5"
+version = "0.4.6"
 
 [dependencies.parking_lot_core]
-version = "0.8.4"
+version = "0.9.0"
 [dev-dependencies.bincode]
 version = "1.3.3"
 
@@ -38,9 +35,8 @@
 arc_lock = ["lock_api/arc_lock"]
 deadlock_detection = ["parking_lot_core/deadlock_detection"]
 default = []
+hardware-lock-elision = []
 nightly = ["parking_lot_core/nightly", "lock_api/nightly"]
 owning_ref = ["lock_api/owning_ref"]
 send_guard = []
 serde = ["lock_api/serde"]
-stdweb = ["instant/stdweb"]
-wasm-bindgen = ["instant/wasm-bindgen"]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 4c2518e..bb501be 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "parking_lot"
-version = "0.11.2"
+version = "0.12.0"
 authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
 description = "More compact and efficient implementations of the standard synchronization primitives."
 license = "Apache-2.0/MIT"
@@ -11,9 +11,8 @@
 edition = "2018"
 
 [dependencies]
-parking_lot_core = { path = "core", version = "0.8.4" }
-lock_api = { path = "lock_api", version = "0.4.5" }
-instant = "0.1.9"
+parking_lot_core = { path = "core", version = "0.9.0" }
+lock_api = { path = "lock_api", version = "0.4.6" }
 
 [dev-dependencies]
 rand = "0.8.3"
@@ -28,9 +27,8 @@
 nightly = ["parking_lot_core/nightly", "lock_api/nightly"]
 deadlock_detection = ["parking_lot_core/deadlock_detection"]
 serde = ["lock_api/serde"]
-stdweb = ["instant/stdweb"]
-wasm-bindgen = ["instant/wasm-bindgen"]
 send_guard = []
+hardware-lock-elision = []
 
 [workspace]
 exclude = ["benchmark"]
diff --git a/METADATA b/METADATA
index e17f251..10f98ed 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/parking_lot/parking_lot-0.11.2.crate"
+    value: "https://static.crates.io/crates/parking_lot/parking_lot-0.12.0.crate"
   }
-  version: "0.11.2"
+  version: "0.12.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2021
-    month: 9
-    day: 22
+    year: 2022
+    month: 3
+    day: 1
   }
 }
diff --git a/README.md b/README.md
index d3e5b0b..5bda8d8 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,7 @@
    library versions of those types.
 7. `RwLock` takes advantage of hardware lock elision on processors that
    support it, which can lead to huge performance wins with many readers.
+   This must be enabled with the `hardware-lock-elision` feature.
 8. `RwLock` uses a task-fair locking policy, which avoids reader and writer
    starvation, whereas the standard library version makes no guarantees.
 9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will
@@ -93,8 +94,6 @@
 - You will have to use the `const_*` functions (e.g. `const_mutex(val)`) to
   statically initialize the locking primitives. Using e.g. `Mutex::new(val)`
   does not work on stable Rust yet.
-- `RwLock` will not be able to take advantage of hardware lock elision for
-  readers, which improves performance when there are multiple readers.
 - The `wasm32-unknown-unknown` target is only supported on nightly and requires
   `-C target-feature=+atomics` in `RUSTFLAGS`.
 
@@ -126,13 +125,17 @@
 Note that the `deadlock_detection` and `send_guard` features are incompatible
 and cannot be used together.
 
+Hardware lock elision support for x86 can be enabled with the
+`hardware-lock-elision` feature. This requires Rust 1.59 due to the use of
+inline assembly.
+
 The core parking lot API is provided by the `parking_lot_core` crate. It is
 separate from the synchronization primitives in the `parking_lot` crate so that
 changes to the core API do not cause breaking changes for users of `parking_lot`.
 
 ## Minimum Rust version
 
-The current minimum required Rust version is 1.36. Any change to this is
+The current minimum required Rust version is 1.49. Any change to this is
 considered a breaking change and will require a major version bump.
 
 ## License
diff --git a/src/condvar.rs b/src/condvar.rs
index 534b8af..9eaf300 100644
--- a/src/condvar.rs
+++ b/src/condvar.rs
@@ -12,10 +12,9 @@
     fmt, ptr,
     sync::atomic::{AtomicPtr, Ordering},
 };
-use instant::Instant;
 use lock_api::RawMutex as RawMutex_;
 use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN};
-use std::time::Duration;
+use std::time::{Duration, Instant};
 
 /// A type indicating whether a timed wait on a condition variable returned
 /// due to a time out or not.
@@ -381,12 +380,6 @@
     ///
     /// Like `wait`, the lock specified will be re-acquired when this function
     /// returns, regardless of whether the timeout elapsed or not.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the given `timeout` is so large that it can't be added to the current time.
-    /// This panic is not possible if the crate is built with the `nightly` feature, then a too
-    /// large `timeout` becomes equivalent to just calling `wait`.
     #[inline]
     pub fn wait_for<T: ?Sized>(
         &self,
@@ -414,11 +407,11 @@
 #[cfg(test)]
 mod tests {
     use crate::{Condvar, Mutex, MutexGuard};
-    use instant::Instant;
     use std::sync::mpsc::channel;
     use std::sync::Arc;
     use std::thread;
     use std::time::Duration;
+    use std::time::Instant;
 
     #[test]
     fn smoke() {
@@ -557,14 +550,7 @@
             let _g = m2.lock();
             c2.notify_one();
         });
-        // Non-nightly panics on too large timeouts. Nightly treats it as indefinite wait.
-        let very_long_timeout = if cfg!(feature = "nightly") {
-            Duration::from_secs(u64::max_value())
-        } else {
-            Duration::from_millis(u32::max_value() as u64)
-        };
-
-        let timeout_res = c.wait_for(&mut g, very_long_timeout);
+        let timeout_res = c.wait_for(&mut g, Duration::from_secs(u64::max_value()));
         assert!(!timeout_res.timed_out());
 
         drop(g);
diff --git a/src/elision.rs b/src/elision.rs
index 68cfa63..8fa229e 100644
--- a/src/elision.rs
+++ b/src/elision.rs
@@ -5,6 +5,8 @@
 // http://opensource.org/licenses/MIT>, at your option. This file may not be
 // copied, modified, or distributed except according to those terms.
 
+#[cfg(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64")))]
+use std::arch::asm;
 use std::sync::atomic::AtomicUsize;
 
 // Extension trait to add lock elision primitives to atomic types
@@ -26,14 +28,14 @@
 #[inline]
 pub fn have_elision() -> bool {
     cfg!(all(
-        feature = "nightly",
+        feature = "hardware-lock-elision",
         any(target_arch = "x86", target_arch = "x86_64"),
     ))
 }
 
 // This implementation is never actually called because it is guarded by
 // have_elision().
-#[cfg(not(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"))))]
+#[cfg(not(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64"))))]
 impl AtomicElisionExt for AtomicUsize {
     type IntType = usize;
 
@@ -48,37 +50,33 @@
     }
 }
 
-#[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))]
+#[cfg(all(feature = "hardware-lock-elision", any(target_arch = "x86", target_arch = "x86_64")))]
 impl AtomicElisionExt for AtomicUsize {
     type IntType = usize;
 
-    #[cfg(target_pointer_width = "32")]
     #[inline]
     fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
         unsafe {
+            use core::arch::asm;
             let prev: usize;
-            llvm_asm!("xacquire; lock; cmpxchgl $2, $1"
-                      : "={eax}" (prev), "+*m" (self)
-                      : "r" (new), "{eax}" (current)
-                      : "memory"
-                      : "volatile");
-            if prev == current {
-                Ok(prev)
-            } else {
-                Err(prev)
-            }
-        }
-    }
-    #[cfg(target_pointer_width = "64")]
-    #[inline]
-    fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
-        unsafe {
-            let prev: usize;
-            llvm_asm!("xacquire; lock; cmpxchgq $2, $1"
-                      : "={rax}" (prev), "+*m" (self)
-                      : "r" (new), "{rax}" (current)
-                      : "memory"
-                      : "volatile");
+            #[cfg(target_pointer_width = "32")]
+            asm!(
+                "xacquire",
+                "lock",
+                "cmpxchg [{:e}], {:e}",
+                in(reg) self,
+                in(reg) new,
+                inout("eax") current => prev,
+            );
+            #[cfg(target_pointer_width = "64")]
+            asm!(
+                "xacquire",
+                "lock",
+                "cmpxchg [{}], {}",
+                in(reg) self,
+                in(reg) new,
+                inout("rax") current => prev,
+            );
             if prev == current {
                 Ok(prev)
             } else {
@@ -87,29 +85,27 @@
         }
     }
 
-    #[cfg(target_pointer_width = "32")]
     #[inline]
     fn elision_fetch_sub_release(&self, val: usize) -> usize {
         unsafe {
+            use core::arch::asm;
             let prev: usize;
-            llvm_asm!("xrelease; lock; xaddl $2, $1"
-                      : "=r" (prev), "+*m" (self)
-                      : "0" (val.wrapping_neg())
-                      : "memory"
-                      : "volatile");
-            prev
-        }
-    }
-    #[cfg(target_pointer_width = "64")]
-    #[inline]
-    fn elision_fetch_sub_release(&self, val: usize) -> usize {
-        unsafe {
-            let prev: usize;
-            llvm_asm!("xrelease; lock; xaddq $2, $1"
-                      : "=r" (prev), "+*m" (self)
-                      : "0" (val.wrapping_neg())
-                      : "memory"
-                      : "volatile");
+            #[cfg(target_pointer_width = "32")]
+            asm!(
+                "xrelease",
+                "lock",
+                "xadd [{:e}], {:e}",
+                in(reg) self,
+                inout(reg) val.wrapping_neg() => prev,
+            );
+            #[cfg(target_pointer_width = "64")]
+            asm!(
+                "xrelease",
+                "lock",
+                "xadd [{}], {}",
+                in(reg) self,
+                inout(reg) val.wrapping_neg() => prev,
+            );
             prev
         }
     }
diff --git a/src/fair_mutex.rs b/src/fair_mutex.rs
index 449c53b..3e4c163 100644
--- a/src/fair_mutex.rs
+++ b/src/fair_mutex.rs
@@ -11,24 +11,21 @@
 /// A mutual exclusive primitive that is always fair, useful for protecting shared data
 ///
 /// This mutex will block threads waiting for the lock to become available. The
-/// mutex can also be statically initialized or created via a `new`
+/// mutex can be statically initialized or created by the `new`
 /// constructor. Each mutex has a type parameter which represents the data that
 /// it is protecting. The data can only be accessed through the RAII guards
 /// returned from `lock` and `try_lock`, which guarantees that the data is only
 /// ever accessed when the mutex is locked.
 ///
-/// The regular mutex provided by `parking_lot` uses eventual locking fairness
+/// The regular mutex provided by `parking_lot` uses eventual fairness
 /// (after some time it will default to the fair algorithm), but eventual
-/// fairness does not provide the same garantees a always fair method would.
-/// Fair mutexes are generally slower, but sometimes needed. This wrapper was
-/// created to avoid using a unfair protocol when it's forbidden by mistake.
+/// fairness does not provide the same guarantees an always fair method would.
+/// Fair mutexes are generally slower, but sometimes needed.
 ///
-/// In a fair mutex the lock is provided to whichever thread asked first,
-/// they form a queue and always follow the first-in first-out order. This
-/// means some thread in the queue won't be able to steal the lock and use it fast
-/// to increase throughput, at the cost of latency. Since the response time will grow
-/// for some threads that are waiting for the lock and losing to faster but later ones,
-/// but it may make sending more responses possible.
+/// In a fair mutex the waiters form a queue, and the lock is always granted to
+/// the next requester in the queue, in first-in first-out order. This ensures
+/// that one thread cannot starve others by quickly re-acquiring the lock after
+/// releasing it.
 ///
 /// A fair mutex may not be interesting if threads have different priorities (this is known as
 /// priority inversion).
diff --git a/src/lib.rs b/src/lib.rs
index 7ff2c79..03639a6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,6 @@
 
 #![warn(missing_docs)]
 #![warn(rust_2018_idioms)]
-#![cfg_attr(feature = "nightly", feature(llvm_asm))]
 
 mod condvar;
 mod elision;
diff --git a/src/mutex.rs b/src/mutex.rs
index 9f63cb9..71bc351 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -11,7 +11,7 @@
 /// A mutual exclusion primitive useful for protecting shared data
 ///
 /// This mutex will block threads waiting for the lock to become available. The
-/// mutex can also be statically initialized or created via a `new`
+/// mutex can be statically initialized or created by the `new`
 /// constructor. Each mutex has a type parameter which represents the data that
 /// it is protecting. The data can only be accessed through the RAII guards
 /// returned from `lock` and `try_lock`, which guarantees that the data is only
diff --git a/src/raw_mutex.rs b/src/raw_mutex.rs
index 06667d3..b1ae7ee 100644
--- a/src/raw_mutex.rs
+++ b/src/raw_mutex.rs
@@ -10,9 +10,9 @@
     sync::atomic::{AtomicU8, Ordering},
     time::Duration,
 };
-use instant::Instant;
 use lock_api::RawMutex as RawMutex_;
 use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN};
+use std::time::Instant;
 
 // UnparkToken used to indicate that that the target thread should attempt to
 // lock the mutex again as soon as it is unparked.
diff --git a/src/raw_rwlock.rs b/src/raw_rwlock.rs
index 19b61c8..21d338b 100644
--- a/src/raw_rwlock.rs
+++ b/src/raw_rwlock.rs
@@ -12,12 +12,11 @@
     cell::Cell,
     sync::atomic::{AtomicUsize, Ordering},
 };
-use instant::Instant;
 use lock_api::{RawRwLock as RawRwLock_, RawRwLockUpgrade};
 use parking_lot_core::{
     self, deadlock, FilterOp, ParkResult, ParkToken, SpinWait, UnparkResult, UnparkToken,
 };
-use std::time::Duration;
+use std::time::{Duration, Instant};
 
 // This reader-writer lock implementation is based on Boost's upgrade_mutex:
 // https://github.com/boostorg/thread/blob/fc08c1fe2840baeeee143440fba31ef9e9a813c8/include/boost/thread/v2/shared_mutex.hpp#L432
@@ -144,6 +143,12 @@
         let state = self.state.load(Ordering::Relaxed);
         state & (WRITER_BIT | READERS_MASK) != 0
     }
+
+    #[inline]
+    fn is_locked_exclusive(&self) -> bool {
+        let state = self.state.load(Ordering::Relaxed);
+        state & (WRITER_BIT) != 0
+    }
 }
 
 unsafe impl lock_api::RawRwLockFair for RawRwLock {
diff --git a/src/rwlock.rs b/src/rwlock.rs
index 70e1b1a..512114c 100644
--- a/src/rwlock.rs
+++ b/src/rwlock.rs
@@ -408,6 +408,8 @@
                 write_result.is_none(),
                 "try_write should fail while read_guard is in scope"
             );
+            assert!(lock.is_locked());
+            assert!(!lock.is_locked_exclusive());
 
             drop(read_guard);
         }
@@ -419,6 +421,8 @@
                 write_result.is_none(),
                 "try_write should fail while upgrade_guard is in scope"
             );
+            assert!(lock.is_locked());
+            assert!(!lock.is_locked_exclusive());
 
             drop(upgrade_guard);
         }
@@ -430,6 +434,8 @@
                 write_result.is_none(),
                 "try_write should fail while write_guard is in scope"
             );
+            assert!(lock.is_locked());
+            assert!(lock.is_locked_exclusive());
 
             drop(write_guard);
         }
@@ -615,4 +621,22 @@
         .join()
         .unwrap();
     }
+
+    #[test]
+    fn test_rw_write_is_locked() {
+        let lock = RwLock::new(0isize);
+        {
+            let _read_guard = lock.read();
+
+            assert!(lock.is_locked());
+            assert!(!lock.is_locked_exclusive());
+        }
+
+        {
+            let _write_guard = lock.write();
+
+            assert!(lock.is_locked());
+            assert!(lock.is_locked_exclusive());
+        }
+    }
 }
diff --git a/src/util.rs b/src/util.rs
index 19cc2c2..c5496fc 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -5,8 +5,7 @@
 // http://opensource.org/licenses/MIT>, at your option. This file may not be
 // copied, modified, or distributed except according to those terms.
 
-use instant::Instant;
-use std::time::Duration;
+use std::time::{Duration, Instant};
 
 // Option::unchecked_unwrap
 pub trait UncheckedOptionExt<T> {