github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/timer/timer-internal.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package timer 4 5 import ( 6 "sync/atomic" 7 "unsafe" 8 9 "../cpu" 10 "../protocol" 11 "../race" 12 "../time/monotonic" 13 ) 14 15 // when is a helper function for setting the 'when' field of a Timer. 16 // It returns what the time will be, in nanoseconds, Duration d in the future. 17 // If d is negative, it is ignored. If the returned value would be less than 18 // zero because of an overflow, MaxInt64 is returned. 19 func when(d protocol.Duration) (t int64) { 20 t = monotonic.RuntimeNano() 21 if d <= 0 { 22 return 23 } 24 t += int64(d) 25 // check for overflow. 26 if t < 0 { 27 // N.B. monotonic.RuntimeNano() and d are always positive, so addition 28 // (including overflow) will never result in t == 0. 29 t = maxWhen 30 } 31 return 32 } 33 34 // use to prevent memory leak 35 func (t *Timer) reset() { 36 t.callback = nil 37 t.arg = nil 38 t.timers = nil 39 } 40 41 // add adds a timer to the running cpu core timers. 42 // This should only be called with a newly created timer. 43 // That avoids the risk of changing the when field of a timer in some P's heap, 44 // which could cause the heap to become unsorted. 45 func (t *Timer) add(d protocol.Duration) { 46 if t.callback == nil { 47 panic("timer: Timer must initialized before start") 48 } 49 if t.status != status_Unset { 50 panic("timer: start called with initialized timer") 51 } 52 if t.timers != nil { 53 panic("timer: timers already set in timer") 54 } 55 // when must be positive. A negative value will cause ts.runTimer to 56 // overflow during its delta calculation and never expire other runtime timers. 57 // Zero will cause checkTimers to fail to notice the timer. 58 if d < 1 { 59 panic("timer: timer must have positive duration.") 60 } 61 62 if race.DetectorEnabled { 63 race.Release(unsafe.Pointer(t)) 64 } 65 t.when = when(d) 66 t.status = status_Waiting 67 t.timers = &poolByCores[cpu.ActiveCoreID()] 68 t.timers.addTimer(t) 69 } 70 71 // delete deletes the timer t. It may be on some other P, so we can't 72 // actually remove it from the timers heap. We can only mark it as deleted. 73 // It will be removed in due course by the P whose heap it is on. 74 // Reports whether the timer was removed before it was run. 75 func (t *Timer) delete() bool { 76 if t.callback == nil { 77 panic("timer: Stop called on uninitialized Timer") 78 } 79 80 for { 81 var status = t.status.Load() 82 switch status { 83 case status_Waiting, status_ModifiedLater: 84 if t.status.CompareAndSwap(status, status_Modifying) { 85 // Must fetch t.timers before changing status, 86 // as ts.cleanTimers in another goroutine can clear t.timers of a status_Deleted timer. 87 var timers = t.timers 88 if !t.status.CompareAndSwap(status_Modifying, status_Deleted) { 89 badTimer() 90 } 91 atomic.AddInt32(&timers.deletedTimers, 1) 92 // Timer was not yet run. 93 return true 94 } 95 case status_ModifiedEarlier: 96 if t.status.CompareAndSwap(status, status_Modifying) { 97 var timers = t.timers 98 if !t.status.CompareAndSwap(status_Modifying, status_Deleted) { 99 badTimer() 100 } 101 atomic.AddInt32(&timers.deletedTimers, 1) 102 // Timer was not yet run. 103 return true 104 } 105 case status_Deleted, status_Removing, status_Removed: 106 // Timer was already run. 107 return false 108 case status_Running, status_Moving: 109 // The timer is being run or moved, by a different P. 110 // Wait for it to complete. 111 osyield() 112 case status_Unset: 113 // Removing timer that was never added or 114 // has already been run. Also see issue 21874. 115 return false 116 case status_Modifying: 117 // Simultaneous calls to delete and modify. 118 // Wait for the other call to complete. 119 osyield() 120 default: 121 badTimer() 122 } 123 } 124 } 125 126 // modify modifies an existing timer. 127 // It's OK to call modify() on a newly allocated Timer. 128 // Reports whether the timer was modified before it was run. 129 func (t *Timer) modify(d protocol.Duration) (pending bool) { 130 // when must be positive. A negative value will cause ts.runTimer to 131 // overflow during its delta calculation and never expire other runtime timers. 132 // Zero will cause checkTimers to fail to notice the timer. 133 if d < 1 { 134 panic("timer: timer must have positive duration") 135 } 136 if t.callback == nil { 137 panic("timer: Timer must initialized before reset") 138 } 139 140 if race.DetectorEnabled { 141 race.Release(unsafe.Pointer(t)) 142 } 143 144 var wasRemoved = false 145 loop: 146 for { 147 var status = t.status.Load() 148 switch status { 149 case status_Waiting, status_ModifiedEarlier, status_ModifiedLater: 150 if t.status.CompareAndSwap(status, status_Modifying) { 151 pending = true // timer not yet run 152 break loop 153 } 154 case status_Unset, status_Removed: 155 // Timer was already run and t is no longer in a heap. 156 // Act like addTimer. 157 if t.status.CompareAndSwap(status, status_Modifying) { 158 wasRemoved = true 159 pending = false // timer already run or stopped 160 break loop 161 } 162 case status_Deleted: 163 if t.status.CompareAndSwap(status, status_Modifying) { 164 atomic.AddInt32(&t.timers.deletedTimers, -1) 165 pending = false // timer already stopped 166 break loop 167 } 168 case status_Running, status_Removing, status_Moving: 169 // The timer is being run or moved, by a different P. 170 // Wait for it to complete. 171 osyield() 172 case status_Modifying: 173 // Multiple simultaneous calls to modify. 174 // Wait for the other call to complete. 175 osyield() 176 default: 177 badTimer() 178 } 179 } 180 181 var timerOldWhen = t.when 182 var timerNewWhen = when(d) 183 t.when = timerNewWhen 184 if t.period != 0 { 185 t.period = int64(d) 186 } 187 if wasRemoved { 188 t.timers = poolByCores[cpu.ActiveCoreID()] 189 t.timers.addTimer(t) 190 if !t.status.CompareAndSwap(status_Modifying, status_Waiting) { 191 badTimer() 192 } 193 } else { 194 var newStatus = status_ModifiedLater 195 if timerNewWhen < timerOldWhen { 196 newStatus = status_ModifiedEarlier 197 } 198 if newStatus == status_ModifiedEarlier { 199 t.timers.updateTimerModifiedEarliest(timerNewWhen) 200 } 201 202 // Set the new status of the timer. 203 if !t.status.CompareAndSwap(status_Modifying, newStatus) { 204 badTimer() 205 } 206 } 207 208 return 209 }