github.com/zhiqiangxu/util@v0.0.0-20230112053021-0a7aee056cd5/lf/mcas/mcas.go (about)

     1  package mcas
     2  
     3  import (
     4  	"sort"
     5  	"sync/atomic"
     6  	"unsafe"
     7  )
     8  
     9  type mcDesc struct {
    10  	a []*unsafe.Pointer
    11  	e []unsafe.Pointer
    12  	n []unsafe.Pointer
    13  	s uint32
    14  }
    15  
    16  const (
    17  	undecided uint32 = iota
    18  	failed
    19  	successful
    20  )
    21  
    22  func isMCDesc(v unsafe.Pointer) bool {
    23  	return uintptr(v)&addrMask == mcDescAddr
    24  }
    25  
    26  const (
    27  	mcDescAddr = 1
    28  	ccDescAddr = 2
    29  	addrMask   = 3
    30  )
    31  
    32  func mcfromPointer(v unsafe.Pointer) *mcDesc {
    33  	ptr := uintptr(v)
    34  	ptr = ptr & ^uintptr(addrMask)
    35  	return (*mcDesc)(are.getPointer(ptr))
    36  }
    37  
    38  func (d *mcDesc) toPointer() unsafe.Pointer {
    39  	return unsafe.Pointer(uintptr(unsafe.Pointer(d)) + uintptr(mcDescAddr))
    40  }
    41  
    42  func (d *mcDesc) sortAddr() {
    43  	sort.Slice(d.a, func(i, j int) bool {
    44  		return uintptr(unsafe.Pointer(d.a[i])) < uintptr(unsafe.Pointer(d.a[j]))
    45  	})
    46  }
    47  
    48  func (d *mcDesc) status() uint32 {
    49  	return atomic.LoadUint32(&d.s)
    50  }
    51  
    52  func (d *mcDesc) mcasHelp() (suc bool) {
    53  	ds := failed
    54  	var (
    55  		v unsafe.Pointer
    56  	)
    57  	/* PHASE 1: Attempt to acquire each location in turn. */
    58  	for i := range d.a {
    59  		for {
    60  			ccas(d.a[i], d.e[i], d.toPointer(), &d.s)
    61  			v = atomic.LoadPointer(d.a[i])
    62  			if v == d.toPointer() {
    63  				break
    64  			}
    65  
    66  			if isCCDesc(v) {
    67  				ccfromPointer(v).ccasHelp()
    68  				continue
    69  			} else if isMCDesc(v) {
    70  				mcfromPointer(v).mcasHelp()
    71  				continue
    72  			}
    73  
    74  			// v is plain pointer value
    75  
    76  			if v == d.e[i] && d.status() == undecided {
    77  				continue
    78  			}
    79  
    80  			goto decision_point
    81  		}
    82  	}
    83  
    84  	ds = successful
    85  
    86  decision_point:
    87  
    88  	atomic.CompareAndSwapUint32(&d.s, undecided, ds)
    89  
    90  	/* PHASE 2: Release each location that we hold. */
    91  	suc = atomic.LoadUint32(&d.s) == successful
    92  	for i := range d.a {
    93  		if suc {
    94  			atomic.CompareAndSwapPointer(d.a[i], d.toPointer(), d.n[i])
    95  		} else {
    96  			atomic.CompareAndSwapPointer(d.a[i], d.toPointer(), d.e[i])
    97  		}
    98  	}
    99  
   100  	return
   101  }