@@ -9,8 +9,8 @@ use core::sync::atomic::Ordering;
99
1010use crate :: alloc:: alloc;
1111use crate :: alloc:: boxed:: Box ;
12- use crate :: primitive:: sync:: atomic:: AtomicUsize ;
1312use crate :: guard:: Guard ;
13+ use crate :: primitive:: sync:: atomic:: AtomicUsize ;
1414use crossbeam_utils:: atomic:: AtomicConsume ;
1515
1616/// Given ordering for the success case in a compare-exchange operation, returns the strongest
@@ -26,17 +26,22 @@ fn strongest_failure_ordering(ord: Ordering) -> Ordering {
2626}
2727
2828/// The error returned on failed compare-and-set operation.
29- pub struct CompareAndSetError < ' g , T : ?Sized + Pointable , P : Pointer < T > > {
29+ // TODO: remove in the next major version.
30+ #[ deprecated( note = "Use `CompareExchangeError` instead" ) ]
31+ pub type CompareAndSetError < ' g , T , P > = CompareExchangeError < ' g , T , P > ;
32+
33+ /// The error returned on failed compare-and-swap operation.
34+ pub struct CompareExchangeError < ' g , T : ?Sized + Pointable , P : Pointer < T > > {
3035 /// The value in the atomic pointer at the time of the failed operation.
3136 pub current : Shared < ' g , T > ,
3237
3338 /// The new value, which the operation failed to store.
3439 pub new : P ,
3540}
3641
37- impl < ' g , T : ' g , P : Pointer < T > + fmt:: Debug > fmt:: Debug for CompareAndSetError < ' g , T , P > {
42+ impl < T , P : Pointer < T > + fmt:: Debug > fmt:: Debug for CompareExchangeError < ' _ , T , P > {
3843 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
39- f. debug_struct ( "CompareAndSetError " )
44+ f. debug_struct ( "CompareExchangeError " )
4045 . field ( "current" , & self . current )
4146 . field ( "new" , & self . new )
4247 . finish ( )
@@ -54,6 +59,11 @@ impl<'g, T: 'g, P: Pointer<T> + fmt::Debug> fmt::Debug for CompareAndSetError<'g
5459/// ordering is chosen.
5560/// 2. A pair of `Ordering`s. The first one is for the success case, while the second one is
5661/// for the failure case.
62+ // TODO: remove in the next major version.
63+ #[ deprecated(
64+ note = "`compare_and_set` and `compare_and_set_weak` that use this trait are deprecated, \
65+ use `compare_exchange` or `compare_exchange_weak instead`"
66+ ) ]
5767pub trait CompareAndSetOrdering {
5868 /// The ordering of the operation when it succeeds.
5969 fn success ( & self ) -> Ordering ;
@@ -65,6 +75,7 @@ pub trait CompareAndSetOrdering {
6575 fn failure ( & self ) -> Ordering ;
6676}
6777
78+ #[ allow( deprecated) ]
6879impl CompareAndSetOrdering for Ordering {
6980 #[ inline]
7081 fn success ( & self ) -> Ordering {
@@ -77,6 +88,7 @@ impl CompareAndSetOrdering for Ordering {
7788 }
7889}
7990
91+ #[ allow( deprecated) ]
8092impl CompareAndSetOrdering for ( Ordering , Ordering ) {
8193 #[ inline]
8294 fn success ( & self ) -> Ordering {
@@ -426,8 +438,14 @@ impl<T: ?Sized + Pointable> Atomic<T> {
426438 /// pointer that was written is returned. On failure the actual current value and `new` are
427439 /// returned.
428440 ///
429- /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory
430- /// ordering of this operation.
441+ /// This method takes two `Ordering` arguments to describe the memory
442+ /// ordering of this operation. `success` describes the required ordering for the
443+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
444+ /// `failure` describes the required ordering for the load operation that takes place when
445+ /// the comparison fails. Using `Acquire` as success ordering makes the store part
446+ /// of this operation `Relaxed`, and using `Release` makes the successful load
447+ /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed`
448+ /// and must be equivalent to or weaker than the success ordering.
431449 ///
432450 /// # Examples
433451 ///
@@ -439,32 +457,162 @@ impl<T: ?Sized + Pointable> Atomic<T> {
439457 ///
440458 /// let guard = &epoch::pin();
441459 /// let curr = a.load(SeqCst, guard);
442- /// let res1 = a.compare_and_set (curr, Shared::null(), SeqCst, guard);
443- /// let res2 = a.compare_and_set (curr, Owned::new(5678), SeqCst, guard);
460+ /// let res1 = a.compare_exchange (curr, Shared::null(), SeqCst , SeqCst, guard);
461+ /// let res2 = a.compare_exchange (curr, Owned::new(5678), SeqCst , SeqCst, guard);
444462 /// ```
445- pub fn compare_and_set < ' g , O , P > (
463+ pub fn compare_exchange < ' g , P > (
446464 & self ,
447465 current : Shared < ' _ , T > ,
448466 new : P ,
449- ord : O ,
467+ success : Ordering ,
468+ failure : Ordering ,
450469 _: & ' g Guard ,
451- ) -> Result < Shared < ' g , T > , CompareAndSetError < ' g , T , P > >
470+ ) -> Result < Shared < ' g , T > , CompareExchangeError < ' g , T , P > >
452471 where
453- O : CompareAndSetOrdering ,
454472 P : Pointer < T > ,
455473 {
456474 let new = new. into_usize ( ) ;
457475 self . data
458- . compare_exchange ( current. into_usize ( ) , new, ord . success ( ) , ord . failure ( ) )
476+ . compare_exchange ( current. into_usize ( ) , new, success, failure)
459477 . map ( |_| unsafe { Shared :: from_usize ( new) } )
460478 . map_err ( |current| unsafe {
461- CompareAndSetError {
479+ CompareExchangeError {
462480 current : Shared :: from_usize ( current) ,
463481 new : P :: from_usize ( new) ,
464482 }
465483 } )
466484 }
467485
486+ /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current
487+ /// value is the same as `current`. The tag is also taken into account, so two pointers to the
488+ /// same object, but with different tags, will not be considered equal.
489+ ///
490+ /// Unlike [`compare_exchange`], this method is allowed to spuriously fail even when comparison
491+ /// succeeds, which can result in more efficient code on some platforms. The return value is a
492+ /// result indicating whether the new pointer was written. On success the pointer that was
493+ /// written is returned. On failure the actual current value and `new` are returned.
494+ ///
495+ /// This method takes two `Ordering` arguments to describe the memory
496+ /// ordering of this operation. `success` describes the required ordering for the
497+ /// read-modify-write operation that takes place if the comparison with `current` succeeds.
498+ /// `failure` describes the required ordering for the load operation that takes place when
499+ /// the comparison fails. Using `Acquire` as success ordering makes the store part
500+ /// of this operation `Relaxed`, and using `Release` makes the successful load
501+ /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed`
502+ /// and must be equivalent to or weaker than the success ordering.
503+ ///
504+ /// [`compare_exchange`]: Atomic::compare_exchange
505+ ///
506+ /// # Examples
507+ ///
508+ /// ```
509+ /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared};
510+ /// use std::sync::atomic::Ordering::SeqCst;
511+ ///
512+ /// let a = Atomic::new(1234);
513+ /// let guard = &epoch::pin();
514+ ///
515+ /// let mut new = Owned::new(5678);
516+ /// let mut ptr = a.load(SeqCst, guard);
517+ /// loop {
518+ /// match a.compare_exchange_weak(ptr, new, SeqCst, SeqCst, guard) {
519+ /// Ok(p) => {
520+ /// ptr = p;
521+ /// break;
522+ /// }
523+ /// Err(err) => {
524+ /// ptr = err.current;
525+ /// new = err.new;
526+ /// }
527+ /// }
528+ /// }
529+ ///
530+ /// let mut curr = a.load(SeqCst, guard);
531+ /// loop {
532+ /// match a.compare_exchange_weak(curr, Shared::null(), SeqCst, SeqCst, guard) {
533+ /// Ok(_) => break,
534+ /// Err(err) => curr = err.current,
535+ /// }
536+ /// }
537+ /// ```
538+ pub fn compare_exchange_weak < ' g , P > (
539+ & self ,
540+ current : Shared < ' _ , T > ,
541+ new : P ,
542+ success : Ordering ,
543+ failure : Ordering ,
544+ _: & ' g Guard ,
545+ ) -> Result < Shared < ' g , T > , CompareExchangeError < ' g , T , P > >
546+ where
547+ P : Pointer < T > ,
548+ {
549+ let new = new. into_usize ( ) ;
550+ self . data
551+ . compare_exchange_weak ( current. into_usize ( ) , new, success, failure)
552+ . map ( |_| unsafe { Shared :: from_usize ( new) } )
553+ . map_err ( |current| unsafe {
554+ CompareExchangeError {
555+ current : Shared :: from_usize ( current) ,
556+ new : P :: from_usize ( new) ,
557+ }
558+ } )
559+ }
560+
561+ /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current
562+ /// value is the same as `current`. The tag is also taken into account, so two pointers to the
563+ /// same object, but with different tags, will not be considered equal.
564+ ///
565+ /// The return value is a result indicating whether the new pointer was written. On success the
566+ /// pointer that was written is returned. On failure the actual current value and `new` are
567+ /// returned.
568+ ///
569+ /// This method takes a [`CompareAndSetOrdering`] argument which describes the memory
570+ /// ordering of this operation.
571+ ///
572+ /// # Migrating to `compare_exchange`
573+ ///
574+ /// `compare_and_set` is equivalent to `compare_exchange` with the following mapping for
575+ /// memory orderings:
576+ ///
577+ /// Original | Success | Failure
578+ /// -------- | ------- | -------
579+ /// Relaxed | Relaxed | Relaxed
580+ /// Acquire | Acquire | Acquire
581+ /// Release | Release | Relaxed
582+ /// AcqRel | AcqRel | Acquire
583+ /// SeqCst | SeqCst | SeqCst
584+ ///
585+ /// # Examples
586+ ///
587+ /// ```
588+ /// # #![allow(deprecated)]
589+ /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared};
590+ /// use std::sync::atomic::Ordering::SeqCst;
591+ ///
592+ /// let a = Atomic::new(1234);
593+ ///
594+ /// let guard = &epoch::pin();
595+ /// let curr = a.load(SeqCst, guard);
596+ /// let res1 = a.compare_and_set(curr, Shared::null(), SeqCst, guard);
597+ /// let res2 = a.compare_and_set(curr, Owned::new(5678), SeqCst, guard);
598+ /// ```
599+ // TODO: remove in the next major version.
600+ #[ allow( deprecated) ]
601+ #[ deprecated( note = "Use `compare_exchange` instead" ) ]
602+ pub fn compare_and_set < ' g , O , P > (
603+ & self ,
604+ current : Shared < ' _ , T > ,
605+ new : P ,
606+ ord : O ,
607+ guard : & ' g Guard ,
608+ ) -> Result < Shared < ' g , T > , CompareAndSetError < ' g , T , P > >
609+ where
610+ O : CompareAndSetOrdering ,
611+ P : Pointer < T > ,
612+ {
613+ self . compare_exchange ( current, new, ord. success ( ) , ord. failure ( ) , guard)
614+ }
615+
468616 /// Stores the pointer `new` (either `Shared` or `Owned`) into the atomic pointer if the current
469617 /// value is the same as `current`. The tag is also taken into account, so two pointers to the
470618 /// same object, but with different tags, will not be considered equal.
@@ -479,9 +627,23 @@ impl<T: ?Sized + Pointable> Atomic<T> {
479627 ///
480628 /// [`compare_and_set`]: Atomic::compare_and_set
481629 ///
630+ /// # Migrating to `compare_exchange_weak`
631+ ///
632+ /// `compare_and_set_weak` is equivalent to `compare_exchange_weak` with the following mapping for
633+ /// memory orderings:
634+ ///
635+ /// Original | Success | Failure
636+ /// -------- | ------- | -------
637+ /// Relaxed | Relaxed | Relaxed
638+ /// Acquire | Acquire | Acquire
639+ /// Release | Release | Relaxed
640+ /// AcqRel | AcqRel | Acquire
641+ /// SeqCst | SeqCst | SeqCst
642+ ///
482643 /// # Examples
483644 ///
484645 /// ```
646+ /// # #![allow(deprecated)]
485647 /// use crossbeam_epoch::{self as epoch, Atomic, Owned, Shared};
486648 /// use std::sync::atomic::Ordering::SeqCst;
487649 ///
@@ -511,27 +673,21 @@ impl<T: ?Sized + Pointable> Atomic<T> {
511673 /// }
512674 /// }
513675 /// ```
676+ // TODO: remove in the next major version.
677+ #[ allow( deprecated) ]
678+ #[ deprecated( note = "Use `compare_exchange_weak` instead" ) ]
514679 pub fn compare_and_set_weak < ' g , O , P > (
515680 & self ,
516681 current : Shared < ' _ , T > ,
517682 new : P ,
518683 ord : O ,
519- _ : & ' g Guard ,
684+ guard : & ' g Guard ,
520685 ) -> Result < Shared < ' g , T > , CompareAndSetError < ' g , T , P > >
521686 where
522687 O : CompareAndSetOrdering ,
523688 P : Pointer < T > ,
524689 {
525- let new = new. into_usize ( ) ;
526- self . data
527- . compare_exchange_weak ( current. into_usize ( ) , new, ord. success ( ) , ord. failure ( ) )
528- . map ( |_| unsafe { Shared :: from_usize ( new) } )
529- . map_err ( |current| unsafe {
530- CompareAndSetError {
531- current : Shared :: from_usize ( current) ,
532- new : P :: from_usize ( new) ,
533- }
534- } )
690+ self . compare_exchange_weak ( current, new, ord. success ( ) , ord. failure ( ) , guard)
535691 }
536692
537693 /// Bitwise "and" with the current tag.
0 commit comments