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 }