Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com

## [Unreleased]

- Allow CAS failure ordering stronger than success ordering.

## [0.3.2] - 2022-06-19

- Optimize x86_64 128-bit atomic load/store on Intel CPU with AVX. ([#16](https://github.com/taiki-e/portable-atomic/pull/16))
Expand Down
4 changes: 3 additions & 1 deletion src/imp/atomic128/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,10 @@ unsafe fn atomic_compare_exchange(
old: u128,
new: u128,
success: Ordering,
_failure: Ordering,
failure: Ordering,
) -> Result<u128, u128> {
let success = crate::utils::upgrade_success_ordering(success, failure);

#[cfg(any(target_feature = "lse", portable_atomic_target_feature = "lse"))]
// SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`.
// cfg guarantee that the CPU supports FEAT_LSE.
Expand Down
5 changes: 4 additions & 1 deletion src/imp/atomic128/powerpc64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,11 @@ unsafe fn atomic_compare_exchange(
old: u128,
new: u128,
success: Ordering,
_failure: Ordering,
failure: Ordering,
) -> Result<u128, u128> {
debug_assert!(dst as usize % 16 == 0);
let success = crate::utils::upgrade_success_ordering(success, failure);

// SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`.
let res = unsafe {
let old = U128 { whole: old };
Expand Down
3 changes: 3 additions & 0 deletions src/imp/atomic128/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ unsafe fn cmpxchg16b(
#[inline]
unsafe fn _atomic_load_vmovdqa(src: *mut u128, _order: Ordering) -> u128 {
debug_assert!(src as usize % 16 == 0);

// SAFETY: the caller must uphold the safety contract for `_atomic_load_vmovdqa`.
unsafe {
let out: core::arch::x86_64::__m128;
Expand All @@ -170,6 +171,7 @@ unsafe fn _atomic_load_vmovdqa(src: *mut u128, _order: Ordering) -> u128 {
#[inline]
unsafe fn _atomic_store_vmovdqa(dst: *mut u128, val: u128, _order: Ordering) {
debug_assert!(dst as usize % 16 == 0);

// SAFETY: the caller must uphold the safety contract for `_atomic_store_vmovdqa`.
unsafe {
let val: core::arch::x86_64::__m128 = core::mem::transmute(val);
Expand Down Expand Up @@ -274,6 +276,7 @@ unsafe fn atomic_compare_exchange(
success: Ordering,
failure: Ordering,
) -> Result<u128, u128> {
let success = crate::utils::upgrade_success_ordering(success, failure);
// SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`.
let (res, ok) = unsafe { cmpxchg16b(dst, old, new, success, failure) };
if ok {
Expand Down
99 changes: 99 additions & 0 deletions src/imp/core_atomic.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// Wrap the standard library's atomic types in newtype.
//
// This is not a reexport, because we want to backport changes like
// https://github.com/rust-lang/rust/pull/98383 to old compilers.

#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))]
#[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr"))]
Expand All @@ -25,6 +28,34 @@ impl AtomicBool {
pub(crate) fn into_inner(self) -> bool {
self.inner.into_inner()
}
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))]
#[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr"))]
#[inline]
pub(crate) fn compare_exchange(
&self,
current: bool,
new: bool,
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange(current, new, success, failure)
}
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))]
#[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr"))]
#[inline]
pub(crate) fn compare_exchange_weak(
&self,
current: bool,
new: bool,
success: Ordering,
failure: Ordering,
) -> Result<bool, bool> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange_weak(current, new, success, failure)
}
}
impl core::ops::Deref for AtomicBool {
type Target = core::sync::atomic::AtomicBool;
Expand Down Expand Up @@ -61,6 +92,34 @@ impl<T> AtomicPtr<T> {
pub(crate) fn into_inner(self) -> *mut T {
self.inner.into_inner()
}
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))]
#[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr"))]
#[inline]
pub(crate) fn compare_exchange(
&self,
current: *mut T,
new: *mut T,
success: Ordering,
failure: Ordering,
) -> Result<*mut T, *mut T> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange(current, new, success, failure)
}
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(not(portable_atomic_no_atomic_cas)))]
#[cfg_attr(not(portable_atomic_no_cfg_target_has_atomic), cfg(target_has_atomic = "ptr"))]
#[inline]
pub(crate) fn compare_exchange_weak(
&self,
current: *mut T,
new: *mut T,
success: Ordering,
failure: Ordering,
) -> Result<*mut T, *mut T> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange_weak(current, new, success, failure)
}
}
impl<T> core::ops::Deref for AtomicPtr<T> {
type Target = core::sync::atomic::AtomicPtr<T>;
Expand Down Expand Up @@ -99,6 +158,46 @@ macro_rules! atomic_int {
pub(crate) fn into_inner(self) -> $int_type {
self.inner.into_inner()
}
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(not(portable_atomic_no_atomic_cas))
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(target_has_atomic = "ptr")
)]
#[inline]
pub(crate) fn compare_exchange(
&self,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$int_type, $int_type> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange(current, new, success, failure)
}
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(not(portable_atomic_no_atomic_cas))
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(target_has_atomic = "ptr")
)]
#[inline]
pub(crate) fn compare_exchange_weak(
&self,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$int_type, $int_type> {
// TODO: add cfg once https://github.com/rust-lang/rust/pull/98383 merged.
let success = crate::utils::upgrade_success_ordering(success, failure);
self.inner.compare_exchange_weak(current, new, success, failure)
}
#[cfg(portable_atomic_no_atomic_min_max)]
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
Expand Down
36 changes: 12 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,7 @@ impl AtomicBool {
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -454,8 +453,7 @@ impl AtomicBool {
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -593,8 +591,7 @@ impl AtomicBool {
/// Using [`Acquire`] as success ordering makes the store part of this
/// operation [`Relaxed`], and using [`Release`] makes the final successful
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
/// success ordering.
/// [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -792,8 +789,7 @@ impl<T> AtomicPtr<T> {
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -827,8 +823,7 @@ impl<T> AtomicPtr<T> {
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -867,8 +862,7 @@ impl<T> AtomicPtr<T> {
/// Using [`Acquire`] as success ordering makes the store part of this
/// operation [`Relaxed`], and using [`Release`] makes the final successful
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
/// success ordering.
/// [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(not(portable_atomic_no_atomic_cas), portable_atomic_unsafe_assume_single_core))
Expand Down Expand Up @@ -1087,8 +1081,7 @@ atomic instructions or locks will be used.
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down Expand Up @@ -1126,8 +1119,7 @@ atomic instructions or locks will be used.
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down Expand Up @@ -1322,8 +1314,7 @@ atomic instructions or locks will be used.
///
/// Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down Expand Up @@ -1585,8 +1576,7 @@ This type has the same in-memory representation as the underlying floating point
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down Expand Up @@ -1632,8 +1622,7 @@ This type has the same in-memory representation as the underlying floating point
/// `failure` describes the required ordering for the load operation that takes place when
/// the comparison fails. Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the successful load
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down Expand Up @@ -1734,8 +1723,7 @@ This type has the same in-memory representation as the underlying floating point
///
/// Using [`Acquire`] as success ordering makes the store part
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`]
/// and must be equivalent to or weaker than the success ordering.
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(
Expand Down
Loading