github.com/coyove/common@v0.0.0-20240403014525-f70e643f9de8/waitobject/wheel.go (about)

     1  package waitobject
     2  
     3  import (
     4  	"sync"
     5  	"sync/atomic"
     6  	"time"
     7  	"unsafe"
     8  )
     9  
    10  type notifier struct {
    11  	deadline int64
    12  	obj      *Object
    13  }
    14  
    15  func (n *notifier) invalidate() {
    16  	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&n.obj)), unsafe.Pointer(uintptr(0)))
    17  }
    18  
    19  func (n *notifier) isvalid() bool {
    20  	return atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&n.obj))) != unsafe.Pointer(uintptr(0))
    21  }
    22  
    23  var (
    24  	timeoutWheel struct {
    25  		secmin [60][60]struct {
    26  			sync.Mutex
    27  			list []*notifier
    28  		}
    29  	}
    30  	debug bool
    31  
    32  	Eternal = (time.Time{}).Add((1 << 60) * time.Nanosecond)
    33  )
    34  
    35  func init() {
    36  	go func() {
    37  		for t := range time.Tick(time.Second) {
    38  			s, m, now := t.Second(), t.Minute(), t.Unix()
    39  
    40  			repeat := false
    41  
    42  		REPEAT:
    43  			ts := &timeoutWheel.secmin[s][m]
    44  			ts.Lock()
    45  			for i := len(ts.list) - 1; i >= 0; i-- {
    46  				n := ts.list[i]
    47  				debugprint("repeated: ", repeat, ", notifier: ", n, ", now: ", now, ", timedout: ", n.deadline > now)
    48  
    49  				if n.deadline > now && n.isvalid() {
    50  					continue
    51  				}
    52  
    53  				// Remove the notifier, and if it is valid, tell its object to time out
    54  				ts.list = append(ts.list[:i], ts.list[i+1:]...)
    55  				if n.isvalid() {
    56  					debugprint("broadcast by wheel")
    57  					n.obj.mu.Lock()
    58  					n.obj.sig.Broadcast()
    59  					n.obj.mu.Unlock()
    60  				}
    61  			}
    62  			ts.Unlock()
    63  
    64  			if !repeat {
    65  				// Dial back 1 second to check if any objects which should time out at "this second"
    66  				// are added to the "previous second" because of clock precision
    67  				t = time.Unix(now-1, 0)
    68  				s, m = t.Second(), t.Minute()
    69  				repeat = true
    70  				goto REPEAT
    71  			}
    72  		}
    73  	}()
    74  }