github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/lf/mcas/ccas.go (about) 1 package mcas 2 3 import ( 4 "sync/atomic" 5 "unsafe" 6 ) 7 8 type ccDesc struct { 9 a *unsafe.Pointer 10 e unsafe.Pointer 11 n unsafe.Pointer 12 sp *uint32 13 } 14 15 func ccasRead(a *unsafe.Pointer) (v unsafe.Pointer) { 16 for v = atomic.LoadPointer(a); isCCDesc(v); v = atomic.LoadPointer(a) { 17 ccfromPointer(v).ccasHelp() 18 } 19 return 20 } 21 22 func isCCDesc(v unsafe.Pointer) bool { 23 return uintptr(v)&addrMask == ccDescAddr 24 } 25 26 func ccfromPointer(v unsafe.Pointer) *ccDesc { 27 ptr := uintptr(v) 28 ptr = ptr & ^uintptr(addrMask) 29 return (*ccDesc)(are.getPointer(ptr)) 30 } 31 32 func (d *ccDesc) toPointer() unsafe.Pointer { 33 return unsafe.Pointer(uintptr(unsafe.Pointer(d)) + uintptr(ccDescAddr)) 34 } 35 36 func ccas(a *unsafe.Pointer, e, n unsafe.Pointer, sp *uint32) (ok, swapped, isn bool) { 37 d := are.putCCDesc() 38 *d = ccDesc{a: a, e: e, n: n, sp: sp} 39 var v unsafe.Pointer 40 for !atomic.CompareAndSwapPointer(d.a, d.e, d.toPointer()) { 41 v = atomic.LoadPointer(d.a) 42 if !isCCDesc(v) { 43 return 44 } 45 ccfromPointer(v).ccasHelp() 46 } 47 ok = true 48 swapped, isn = d.ccasHelp() 49 return 50 } 51 52 func (d *ccDesc) ccasHelp() (swapped, isn bool) { 53 s := atomic.LoadUint32(d.sp) 54 var v unsafe.Pointer 55 if s == undecided { 56 isn = true 57 v = d.n 58 } else { 59 v = d.e 60 } 61 swapped = atomic.CompareAndSwapPointer(d.a, d.toPointer(), v) 62 return 63 }