summaryrefslogtreecommitdiffstats
path: root/vendor/parking_lot/src/elision.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/parking_lot/src/elision.rs')
-rw-r--r--vendor/parking_lot/src/elision.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/vendor/parking_lot/src/elision.rs b/vendor/parking_lot/src/elision.rs
new file mode 100644
index 000000000..8fa229ec7
--- /dev/null
+++ b/vendor/parking_lot/src/elision.rs
@@ -0,0 +1,112 @@
+// Copyright 2016 Amanieu d'Antras
+//
+// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
+// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
+// 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
+pub trait AtomicElisionExt {
+ type IntType;
+
+ // Perform a compare_exchange and start a transaction
+ fn elision_compare_exchange_acquire(
+ &self,
+ current: Self::IntType,
+ new: Self::IntType,
+ ) -> Result<Self::IntType, Self::IntType>;
+
+ // Perform a fetch_sub and end a transaction
+ fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType;
+}
+
+// Indicates whether the target architecture supports lock elision
+#[inline]
+pub fn have_elision() -> bool {
+ cfg!(all(
+ 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 = "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, _: usize, _: usize) -> Result<usize, usize> {
+ unreachable!();
+ }
+
+ #[inline]
+ fn elision_fetch_sub_release(&self, _: usize) -> usize {
+ unreachable!();
+ }
+}
+
+#[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!(
+ "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 {
+ Err(prev)
+ }
+ }
+ }
+
+ #[inline]
+ fn elision_fetch_sub_release(&self, val: usize) -> usize {
+ unsafe {
+ use core::arch::asm;
+ let prev: usize;
+ #[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
+ }
+ }
+}