Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move hardware lock elision support to a separate Cargo feature #313

Merged
merged 1 commit into from Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/rust.yml
Expand Up @@ -25,6 +25,9 @@ jobs:
- channel: nightly
feature: nightly
os: ubuntu
- channel: nightly
feature: hardware-lock-elision
os: ubuntu

steps:
- uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -28,6 +28,7 @@ nightly = ["parking_lot_core/nightly", "lock_api/nightly"]
deadlock_detection = ["parking_lot_core/deadlock_detection"]
serde = ["lock_api/serde"]
send_guard = []
hardware-lock-elision = []

[workspace]
exclude = ["benchmark"]
7 changes: 5 additions & 2 deletions README.md
Expand Up @@ -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
Expand Down Expand Up @@ -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`.

Expand Down Expand Up @@ -126,6 +125,10 @@ 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`.
Expand Down
8 changes: 5 additions & 3 deletions src/elision.rs
Expand Up @@ -26,14 +26,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;

Expand All @@ -48,13 +48,14 @@ 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;

#[inline]
fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result<usize, usize> {
unsafe {
use core::arch::asm;
let prev: usize;
#[cfg(target_pointer_width = "32")]
asm!(
Expand Down Expand Up @@ -85,6 +86,7 @@ impl AtomicElisionExt for AtomicUsize {
#[inline]
fn elision_fetch_sub_release(&self, val: usize) -> usize {
unsafe {
use core::arch::asm;
let prev: usize;
#[cfg(target_pointer_width = "32")]
asm!(
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Expand Up @@ -11,7 +11,6 @@

#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![cfg_attr(feature = "nightly", feature(asm))]

mod condvar;
mod elision;
Expand Down