[M3devel] cas/casp?

Tony Hosking hosking at cs.purdue.edu
Fri Dec 18 19:32:57 CET 2009


Hold your horses.  I am in the middle of working up a more portable "Atomic" interface along the following lines.  We can choose to implement with compiler intrinsics like Word/LongWord (if available), but otherwise will provide a call interface.  I envision instantiating for ADDRESS, CHAR, and Word.T.  This means CAS/CASP will go away.

GENERIC INTERFACE Atomic(Rep);

IMPORT RTMachine;

TYPE T = Rep.T;

PROCEDURE MemoryFence();
  (* Guarantees explicit memory ordering for otherwise unordered atomics, and
     for other memory references wrt atomics.  Not useful for ordering
     ordinary memory references, since those may not race and, if they don't
     race, always appear to be ordered. *)

PROCEDURE CompilerFence();
  (* Ensures that prior memory operations appear in the instruction stream
     before subsequent ones, i.e. the compiler is not allowed to reorder
     around this.  This really has only implementation-defined semantics, but
     it seems to be useful in ensuring ordering with respect to signal
     handlers and the like. *)

PROCEDURE Store(VAR var: T; val: T); (* No ordering guarantees. *)
PROCEDURE StoreRelease(VAR var: T; val: T);

PROCEDURE Load(READONLY var: T): T; (* No ordering guarantees. *)
PROCEDURE LoadAcquire(READONLY var: T): T;

TYPE Order = { Raw, Acquire, Release, Ordered };
     (* "Raw" ==> This operation is unordered, and may become visible to other
        threads in an order that is constrained only by ordering constraints
        on other operations.

        "Release" ==> All prior memory operations (including ordinary
        assignments) become visible to a an acquire operation on the same
        object that sees the resulting value.

        "Acquire" ==> See above.

        "Ordered" ==> Both acquire and release ordering properties.*)

CONST HasCas = RTMachine.HasCas;
CONST HasWaitFreeCas = RTMachine.HasWaitFreeCas;
PROCEDURE Cas(VAR var: T; old, new: T; order := Ordered): T;
  (* Most architectures provide a way to return the old value.  On those that
     do not, it can be emulated with an additional load, at the expense of
     wait-freedom or spurious failure. *)

CONST HasWeakCas = RTMachine.HasWeakCas;
PROCEDURE WeakCas(VAR var: T; old, new: T; order := Ordered): T;
  (* Similar to "Cas", but may fail spuriously, and must be wait-free, if
     provided. *)

CONST HasFetchAdd = RTMachine.HasFetchAdd;
PROCEDURE FetchAdd(VAR var; incr: T; order := Raw): T;

CONST HasFetchOr = RTMachine.HasFetchOr;
PROCEDURE FetchOr(VAR var; mask: T; order := Raw): T;

CONST HasFetchAnd = RTMachine.HasFetchAnd;
PROCEDURE FetchOr(VAR var; mask: T; order := Raw): T;

END Atomic.


On 18 Dec 2009, at 13:04, Jay K wrote:

> Tony is this right?
>  
>  
> conceptually:
>  
>  
> result := CAS(VAR destination, compare, exchange)
>  
>  
> old := destination
> if old := compare then
>   destination = exchange
> return old
>  
>  
> bool result := CASP(VAR destination, compare, exchange)
> P for predicate aka returning bool
>  
>  
> old := destination
> if old = compare then
>   destination := exchange
>   return true
> return false
>  
>  
> I'm pretty sure it is.
>  
>  
> I'll have this for 16 bit and 32 bit values shortly, for now requiring
> a recent Microsoft compiler and it generates function calls.
> But inlining should be easy enough.
> And then 8bit and 64bit.
>  
>  
> Also this will probably not work on 386 or 486 but require Pentium or somesuch.
> I don't know when various instructions were introduced but I know
> 386 is much poorer here than modern processors.
>  
>  
> I assume only support int8, uint8, int16, uint16, int32, uint32, int64, uint64, size_t, ptrdiff_t
> and not e.g. floating point.
>  
>  
>  - Jay




More information about the M3devel mailing list