Languages: English | 简体中文 | 日本語 | Español | Français
Portable 128-bit (double-word) compare-and-swap (CAS) primitive for Go.
- Single atomic 128-bit compare-and-swap (CAS) on amd64/arm64.
- Intended for lock-free algorithms (versioned state, ABA mitigation, composite updates).
- Arm64 uses an LSE pair-CAS fast path by default; LL/SC is available via build tag for compatibility.
go get code.hybscloud.com/dwcas// New returns a 16-byte aligned *Uint128 suitable for 128-bit compare-and-swap.
v := dwcas.New(1, 2)
old := dwcas.Uint128{Lo: 1, Hi: 2}
newv := dwcas.Uint128{Lo: 3, Hi: 4}
prev, swapped := v.AcqRel(old, newv)
fmt.Println(prev, swapped, v.Lo, v.Hi)
type Uint128 struct { Lo uint64; Hi uint64 }
Each method on *dwcas.Uint128 is a 128-bit compare-and-swap in compare-exchange
form.
All methods return:
prev: the value observed in memory at the time of the CAS attemptswapped:trueif the swap happened
Methods:
(*Uint128) Relaxed(old, new Uint128) (prev Uint128, swapped bool)(*Uint128) Acquire(old, new Uint128) (prev Uint128, swapped bool)(*Uint128) Release(old, new Uint128) (prev Uint128, swapped bool)(*Uint128) AcqRel(old, new Uint128) (prev Uint128, swapped bool)
func New(lo, hi uint64) *Uint128func CanPlaceAlignedUint128(p []byte, off int) boolfunc PlaceAlignedUint128(p []byte, off int) (n int, u128 *Uint128)
Ordering is specified per method, with success ordering potentially different from failure ordering:
| Method | Success | Failure |
|---|---|---|
dwcas.Relaxed |
relaxed | relaxed |
dwcas.Acquire |
acquire | relaxed |
dwcas.Release |
release | relaxed |
dwcas.AcqRel |
acq_rel | relaxed |
Notes:
- Some backends are stronger than requested.
- On
amd64,LOCKed operations are at least acquire-release on both success and failure. - On
arm64default (LSE) builds,Release/AcqRelplace a release barrier before the CAS, which also orders a failed attempt.
- On
In rare cases, a caller may need an explicit ordering edge outside the CAS128
primitives. dwcas provides three manual barriers:
dwcas.BarrierAcquire: arm64 emitsDMB ISHLD; amd64 is a compiler barrier only.dwcas.BarrierRelease: arm64 emitsDMB ISHST; amd64 is a compiler barrier only.dwcas.BarrierFull: arm64 emitsDMB ISH; amd64 is a compiler barrier only.
The address of a *dwcas.Uint128 used with these methods must be 16-byte aligned.
The pointer must also be non-nil.
- Default builds perform no runtime checks.
- Opt-in debug guard: build with
-tags=dwcasdebugto panic on nil and misaligned pointers.
Use dwcas.New if you need a heap-allocated 16-byte aligned *Uint128.
If you need to place a *Uint128 inside a caller-provided byte buffer (for
example, in a manually managed arena), use the placement helpers. Worst-case
required remaining bytes from off is 31.
buf := make([]byte, 256)
off := 7
if !dwcas.CanPlaceAlignedUint128(buf, off) {
panic("insufficient space")
}
n, v := dwcas.PlaceAlignedUint128(buf, off)
*v = dwcas.Uint128{Lo: 1, Hi: 2}
_, _ = v.Relaxed(dwcas.Uint128{Lo: 1, Hi: 2}, dwcas.Uint128{Lo: 3, Hi: 4})
off += n // n is in [16..31]
amd64: implemented viaCMPXCHG16B.arm64:- default: LSE pair-CAS (CASP family) (best performance).
- opt-in LL/SC:
-tags=dwcas_llsc(portable baseline viaLDXPwithSTXPorSTLXP).
dwcas uses unsafe and architecture-specific assembly.
- Keep a
*Uint128reachable as a Go pointer. Do not convert it touintptrand back, and do not store it in untracked memory. - A copied
Uint128value does not carry alignment guarantees. Alignment is a property of the address you pass to these methods.
MIT — see LICENSE.
©2025 Hayabusa Cloud Co., Ltd.