github.com/cocotyty/oneshot@v0.0.0-20210707064948-4d5a81d0b747/shot.go (about)

     1  package oneshot
     2  
     3  import (
     4  	"sync/atomic"
     5  	"unsafe"
     6  	_ "unsafe"
     7  )
     8  
     9  type Shot struct {
    10  	gp     uintptr
    11  }
    12  
    13  func getG() uintptr
    14  
    15  //go:linkname gopark runtime.gopark
    16  func gopark(unlockf func(uintptr, unsafe.Pointer) bool, lock unsafe.Pointer, reason byte, traceEv byte, traceskip int)
    17  
    18  //go:linkname goready runtime.goready
    19  func goready(gp uintptr, traceskip int)
    20  
    21  func commit(ug uintptr, xp unsafe.Pointer) bool {
    22  	x := (*Shot)(xp)
    23  	return atomic.CompareAndSwapUintptr(&x.gp, 0, ug)
    24  }
    25  
    26  func (x *Shot) Wait() {
    27  	gopark(commit, unsafe.Pointer(x), 1, 0, 0)
    28  }
    29  
    30  func (x *Shot) WakeUp() {
    31  	ugn := atomic.LoadUintptr(&x.gp)
    32  	if ugn != 0 {
    33  		goready(ugn, 0)
    34  	} else {
    35  		if !atomic.CompareAndSwapUintptr(&x.gp, 0, 1) {
    36  			ugn := atomic.LoadUintptr(&x.gp)
    37  			goready(ugn, 0)
    38  		}
    39  	}
    40  }