github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/ipc/x_block_strategies.go (about)

     1  package ipc
     2  
     3  import (
     4  	"runtime"
     5  	"sync"
     6  	"sync/atomic"
     7  	"time"
     8  	"unsafe"
     9  
    10  	"github.com/benz9527/xboot/lib/infra"
    11  )
    12  
    13  var (
    14  	_ BlockStrategy = (*xGoSchedBlockStrategy)(nil)
    15  	_ BlockStrategy = (*xSleepBlockStrategy)(nil)
    16  	_ BlockStrategy = (*xCpuNoOpLoopBlockStrategy)(nil)
    17  	_ BlockStrategy = (*xOsYieldBlockStrategy)(nil)
    18  	_ BlockStrategy = (*xCacheChannelBlockStrategy)(nil)
    19  	_ BlockStrategy = (*xCondBlockStrategy)(nil)
    20  )
    21  
    22  type xGoSchedBlockStrategy struct{}
    23  
    24  func NewXGoSchedBlockStrategy() BlockStrategy {
    25  	return &xGoSchedBlockStrategy{}
    26  }
    27  
    28  func (x *xGoSchedBlockStrategy) WaitFor(eqFn func() bool) {
    29  	// Let go runtime schedule other goroutines
    30  	// Current goroutine will yield CPU
    31  	runtime.Gosched()
    32  }
    33  
    34  func (x *xGoSchedBlockStrategy) Done() {
    35  	// do nothing
    36  }
    37  
    38  type xSleepBlockStrategy struct {
    39  	sleepTime time.Duration
    40  }
    41  
    42  func NewXSleepBlockStrategy(sleepTime time.Duration) BlockStrategy {
    43  	// around 10us, cpu load 2-3%
    44  	// eq to 5us, cpu load 10%
    45  	// lt 5us, cpu load 100%
    46  	return &xSleepBlockStrategy{
    47  		sleepTime: sleepTime,
    48  	}
    49  }
    50  
    51  func (bs *xSleepBlockStrategy) WaitFor(eqFn func() bool) {
    52  	time.Sleep(bs.sleepTime)
    53  }
    54  
    55  func (bs *xSleepBlockStrategy) Done() {
    56  	// do nothing
    57  }
    58  
    59  type xCpuNoOpLoopBlockStrategy struct {
    60  	cycles uint32
    61  }
    62  
    63  func NewXCpuNoOpLoopBlockStrategy(cycles uint32) BlockStrategy {
    64  	return &xCpuNoOpLoopBlockStrategy{
    65  		cycles: cycles,
    66  	}
    67  }
    68  
    69  func (bs *xCpuNoOpLoopBlockStrategy) WaitFor(eqFn func() bool) {
    70  	infra.ProcYield(bs.cycles)
    71  }
    72  
    73  func (bs *xCpuNoOpLoopBlockStrategy) Done() {}
    74  
    75  type xOsYieldBlockStrategy struct{}
    76  
    77  func NewXOsYieldBlockStrategy() BlockStrategy {
    78  	return &xOsYieldBlockStrategy{}
    79  }
    80  
    81  func (bs *xOsYieldBlockStrategy) WaitFor(fn func() bool) {
    82  	infra.OsYield()
    83  }
    84  
    85  func (bs *xOsYieldBlockStrategy) Done() {}
    86  
    87  type xCacheChannelBlockStrategy struct {
    88  	_      [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte
    89  	status uint64
    90  	_      [cacheLinePadSize - unsafe.Sizeof(*new(uint64))]byte
    91  	ch     chan struct{}
    92  }
    93  
    94  func NewXCacheChannelBlockStrategy() BlockStrategy {
    95  	return &xCacheChannelBlockStrategy{
    96  		ch:     make(chan struct{}, 1),
    97  		status: 0,
    98  	}
    99  }
   100  
   101  func (bs *xCacheChannelBlockStrategy) WaitFor(eqFn func() bool) {
   102  	// Try to block
   103  	if atomic.CompareAndSwapUint64(&bs.status, 0, 1) {
   104  		// Double check
   105  		if !eqFn() {
   106  			// Block, wait for signal
   107  			<-bs.ch
   108  		} else {
   109  			//  Double check failed, reset status
   110  			if !atomic.CompareAndSwapUint64(&bs.status, 1, 0) {
   111  				// Wait for release
   112  				<-bs.ch
   113  			}
   114  		}
   115  	}
   116  }
   117  
   118  func (bs *xCacheChannelBlockStrategy) Done() {
   119  	// Release
   120  	if atomic.CompareAndSwapUint64(&bs.status, 1, 0) {
   121  		// Send signal
   122  		bs.ch <- struct{}{}
   123  	}
   124  }
   125  
   126  // https://gfw.go101.org/article/concurrent-synchronization-more.html
   127  
   128  type xCondBlockStrategy struct {
   129  	cond *sync.Cond
   130  }
   131  
   132  func NewXCondBlockStrategy() BlockStrategy {
   133  	return &xCondBlockStrategy{
   134  		cond: sync.NewCond(&sync.Mutex{}),
   135  	}
   136  }
   137  
   138  func (bs *xCondBlockStrategy) WaitFor(eqFn func() bool) {
   139  	bs.cond.L.Lock()
   140  	defer bs.cond.L.Unlock()
   141  	if eqFn() {
   142  		return
   143  	}
   144  	bs.cond.Wait()
   145  }
   146  
   147  func (bs *xCondBlockStrategy) Done() {
   148  	bs.cond.Broadcast()
   149  }