aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid LeGare <legare@google.com>2022-03-07 22:54:31 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-03-07 22:54:31 +0000
commit181ec76f528292ba01daf9c11dec62e673fafdf6 (patch)
tree90646c4057197db3cc893277c69a189931ccd06c
parent661c5abd6580f4be3083a3c5ac5ce994ba3f3aa7 (diff)
parentbb8a50689a4fcfef776159065580bd8d7e28c7be (diff)
downloadparking_lot-181ec76f528292ba01daf9c11dec62e673fafdf6.tar.gz
Update parking_lot to 0.12.0 am: 468e33c5ab am: 6d325233ff am: b29cce9d8c am: bb8a50689a
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/parking_lot/+/2004796 Change-Id: I590802176ffb1399a2b5c8fd175e86d9d09ad40d
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--.github/workflows/rust.yml11
-rw-r--r--Android.bp3
-rw-r--r--CHANGELOG.md10
-rw-r--r--Cargo.toml12
-rw-r--r--Cargo.toml.orig10
-rw-r--r--METADATA10
-rw-r--r--README.md9
-rw-r--r--src/condvar.rs20
-rw-r--r--src/elision.rs86
-rw-r--r--src/fair_mutex.rs19
-rw-r--r--src/lib.rs1
-rw-r--r--src/mutex.rs2
-rw-r--r--src/raw_mutex.rs2
-rw-r--r--src/raw_rwlock.rs9
-rw-r--r--src/rwlock.rs24
-rw-r--r--src/util.rs3
17 files changed, 127 insertions, 111 deletions
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 @@ name: Rust
on:
push:
- branches-ignore:
- - trying.tmp
- - staging.tmp
+ branches:
+ - trying
+ - staging
pull_request:
-
+
env:
RUST_TEST_THREADS: 1
@@ -25,6 +25,9 @@ jobs:
- 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 @@ rust_library {
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 @@ keywords = ["mutex", "condvar", "rwlock", "once", "thread"]
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 @@ version = "0.8.3"
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 @@ categories = ["concurrency"]
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 @@ owning_ref = ["lock_api/owning_ref"]
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 @@ third_party {
}
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 @@ in the Rust standard library:
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 @@ There are a few restrictions when using this library on stable Rust:
- 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 @@ To allow sending `MutexGuard`s and `RwLock*Guard`s to other threads, enable the
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 @@ use core::{
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 @@ impl Condvar {
///
/// 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 @@ impl fmt::Debug for Condvar {
#[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 @@ mod tests {
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 @@ pub trait AtomicElisionExt {
#[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 @@ impl AtomicElisionExt for AtomicUsize {
}
}
-#[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 @@ impl AtomicElisionExt for AtomicUsize {
}
}
- #[cfg(target_pointer_width = "32")]
- #[inline]
- fn elision_fetch_sub_release(&self, val: usize) -> usize {
- unsafe {
- 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 {
+ use core::arch::asm;
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 @@ use lock_api;
/// 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 @@ use lock_api;
/// 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 @@ use core::{
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 @@ use core::{
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 @@ unsafe impl lock_api::RawRwLock for RawRwLock {
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 @@ mod tests {
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 @@ mod tests {
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 @@ mod tests {
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 @@ mod tests {
.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> {