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  }