Documentation
¶
Overview ¶
Package dwcas provides a portable 128-bit (double-word) compare-and-swap (CAS) primitive for Go.
The core operations are compare-and-swap methods on Uint128 that perform a single atomic read-modify-write on a contiguous 16-byte value.
Intended use cases
- Lock-free algorithms that need to atomically update a value and a version/tag (e.g. ABA mitigation via versioned pointers).
- Composite state machines where two 64-bit words must move together.
- Low-level runtime-like data structures (queues, stacks) where a single 128-bit CAS reduces coordination overhead.
Atomicity and memory ordering ¶
Each method is a single atomic 128-bit compare-and-swap on supported architectures.
Return values ¶
All methods return:
- prev: the value observed in memory at the time of the CAS attempt
- swapped: true if the swap happened
Ordering contracts ¶
Success ordering vs failure ordering:
- Relaxed: success = relaxed, failure = relaxed
- Acquire: success = acquire, failure = relaxed
- Release: success = release, failure = relaxed
- AcqRel: success = acq_rel, failure = relaxed
Some architectures and backends may provide stronger ordering than requested. In particular:
- amd64's LOCKed instructions are at least acquire-release for both success and failure.
- arm64's default LSE backend uses CASPD plus explicit barriers; release-style methods place the release barrier before the CAS, which also orders a failed attempt.
Manual barriers ¶
This package also exposes manual barriers (BarrierAcquire, BarrierRelease, BarrierFull) for callers who need an explicit ordering edge outside the CAS primitives. On arm64 they map to DMB ISH*; on amd64 they are compiler barriers (not MFENCE).
Alignment ¶
The address of a *Uint128 passed to these methods MUST be 16-byte aligned. Misalignment is unsupported and may fault on some CPUs/instructions.
Helpers:
- New returns a heap-allocated 16-byte aligned *Uint128.
- CanPlaceAlignedUint128 / PlaceAlignedUint128 place a 16-byte aligned *Uint128 within a caller-provided byte buffer. The worst-case required remaining bytes from off is 31.
This package intentionally does not perform runtime alignment checks in normal builds. For a debug-only guard, build with `-tags=dwcasdebug` to make these methods panic when called with a misaligned pointer.
Architecture support
- amd64: implemented via CMPXCHG16B.
- arm64: implemented via either LSE pair-CAS (CASP family; default) or LL/SC (opt-in).
- other architectures: building succeeds, but all CAS methods panic at runtime.
Arm64 backend selection
- default: LSE pair-CAS (CASP family; CASPAL semantics)
- opt-in: `-tags=dwcas_llsc` (LL/SC via LDXP with STXP or STLXP)
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BarrierAcquire ¶
func BarrierAcquire()
BarrierAcquire emits an acquire barrier.
This API is intentionally rare and expert-only. Prefer the ordering variants of Uint128 CAS methods when possible.
Semantics by architecture:
- arm64: emits DMB ISHLD.
- amd64: compiler barrier only (prevents compile-time reordering across the call). It is not an MFENCE and is not required for cache coherence.
func BarrierFull ¶
func BarrierFull()
BarrierFull emits a full barrier.
This API is intentionally rare and expert-only. Prefer the ordering variants of Uint128 CAS methods when possible.
Semantics by architecture:
- arm64: emits DMB ISH.
- amd64: compiler barrier only (prevents compile-time reordering across the call). It is not an MFENCE and is not required for cache coherence.
func BarrierRelease ¶
func BarrierRelease()
BarrierRelease emits a release barrier.
This API is intentionally rare and expert-only. Prefer the ordering variants of Uint128 CAS methods when possible.
Semantics by architecture:
- arm64: emits DMB ISHST.
- amd64: compiler barrier only (prevents compile-time reordering across the call). It is not an MFENCE and is not required for cache coherence.
func CanPlaceAlignedUint128 ¶
CanPlaceAlignedUint128 reports whether p has enough remaining capacity from off to place a 16-byte aligned *Uint128 at or after p[off].
Worst-case required remaining bytes from off is 31:
- up to 15 bytes of padding to reach a 16-byte boundary
- 16 bytes for the Uint128 itself
Types ¶
type Uint128 ¶
Uint128 is a 16-byte value used with 128-bit compare-and-swap.
Layout is stable and contiguous in memory:
word 0: Lo word 1: Hi
The address of a *Uint128 used with these methods MUST be 16-byte aligned.
Helpers:
- For heap allocation with guaranteed 16-byte alignment, use New.
- For placing a *Uint128 into a byte buffer, use CanPlaceAlignedUint128 and PlaceAlignedUint128.
func New ¶
New returns a heap-allocated *Uint128 whose address is guaranteed to be 16-byte aligned.
This is primarily a convenience for algorithms that require 16-byte alignment but do not control allocator/layout details (e.g. when a Uint128 cannot be embedded into a manually-aligned struct).
Safety notes:
- The returned pointer refers to Go-managed memory. Keep the *Uint128 reachable (do not convert it to uintptr and back).
- Alignment is guaranteed, but only for the returned pointer itself. If you copy the value into another location, you must re-establish 16-byte alignment.
func PlaceAlignedUint128 ¶
PlaceAlignedUint128 returns a *Uint128 placed within p, starting at or after p[off], such that the returned address is 16-byte aligned.
It returns n, the number of bytes the caller must "consume" starting from off to cover the aligned 16-byte region (including any alignment padding).
The caller is responsible for ensuring CanPlaceAlignedUint128 is true. If not, PlaceAlignedUint128 panics.
Safety notes:
- The returned pointer refers to p's backing array. Keep p reachable.
- Do not convert the returned pointer to uintptr and back.
func (*Uint128) AcqRel ¶
AcqRel is a 128-bit compare-and-swap (CAS) with acquire-release ordering on success and relaxed ordering on failure.
It always returns:
- prev: the value observed in memory at the time of the CAS attempt.
- swapped: true if the swap happened.
Contract:
- p must be non-nil.
- p must be 16-byte aligned.
- On unsupported architectures, AcqRel panics.
func (*Uint128) Acquire ¶
Acquire is a 128-bit compare-and-swap (CAS) with acquire ordering on success and relaxed ordering on failure.
It always returns:
- prev: the value observed in memory at the time of the CAS attempt.
- swapped: true if the swap happened.
Contract:
- p must be non-nil.
- p must be 16-byte aligned.
- On unsupported architectures, Acquire panics.
func (*Uint128) Relaxed ¶
Relaxed is a 128-bit compare-and-swap (CAS) with relaxed ordering on both success and failure.
It always returns:
- prev: the value observed in memory at the time of the CAS attempt.
- swapped: true if the swap happened.
Contract:
- p must be non-nil.
- p must be 16-byte aligned.
- On unsupported architectures, Relaxed panics.
func (*Uint128) Release ¶
Release is a 128-bit compare-and-swap (CAS) with release ordering on success and relaxed ordering on failure.
It always returns:
- prev: the value observed in memory at the time of the CAS attempt.
- swapped: true if the swap happened.
Contract:
- p must be non-nil.
- p must be 16-byte aligned.
- On unsupported architectures, Release panics.