now = nanotime()
}
if now < next {
- return now, next, false
+ // Next timer is not ready to run.
+ // But keep going if we would clear deleted timers.
+ // This corresponds to the condition below where
+ // we decide whether to call clearDeletedTimers.
+ if pp != getg().m.p.ptr() || int(atomic.Load(&pp.deletedTimers)) <= int(atomic.Load(&pp.numTimers)/4) {
+ return now, next, false
+ }
}
}
lock(&pp.timersLock)
moveTimers(plocal, pp.timers)
pp.timers = nil
+ pp.numTimers = 0
pp.adjustTimers = 0
pp.deletedTimers = 0
atomic.Store64(&pp.timer0When, 0)
// Must hold timersLock to access.
timers []*timer
+ // Number of timers in P's heap.
+ // Modified using atomic instructions.
+ numTimers uint32
+
// Number of timerModifiedEarlier timers on P's heap.
// This should only be modified while holding timersLock,
// or while the timer status is in a transient state
// such as timerModifying.
adjustTimers uint32
- // Number of timerDeleted times in P's heap.
+ // Number of timerDeleted timers in P's heap.
// Modified using atomic instructions.
deletedTimers uint32
if t == pp.timers[0] {
atomic.Store64(&pp.timer0When, uint64(t.when))
}
+ atomic.Xadd(&pp.numTimers, 1)
return ok
}
if i == 0 {
updateTimer0When(pp)
}
+ atomic.Xadd(&pp.numTimers, -1)
return ok
}
ok = siftdownTimer(pp.timers, 0)
}
updateTimer0When(pp)
+ atomic.Xadd(&pp.numTimers, -1)
return ok
}
}
if atomic.Load(&pp.adjustTimers) == 0 {
if verifyTimers {
- verifyTimerHeap(pp.timers)
+ verifyTimerHeap(pp)
}
return
}
}
if verifyTimers {
- verifyTimerHeap(pp.timers)
+ verifyTimerHeap(pp)
}
}
timers[i] = nil
}
- timers = timers[:to]
- if verifyTimers {
- verifyTimerHeap(timers)
- }
- pp.timers = timers
atomic.Xadd(&pp.deletedTimers, -cdel)
+ atomic.Xadd(&pp.numTimers, -cdel)
atomic.Xadd(&pp.adjustTimers, -cearlier)
+
+ timers = timers[:to]
+ pp.timers = timers
updateTimer0When(pp)
+
+ if verifyTimers {
+ verifyTimerHeap(pp)
+ }
}
// verifyTimerHeap verifies that the timer heap is in a valid state.
// This is only for debugging, and is only called if verifyTimers is true.
// The caller must have locked the timers.
-func verifyTimerHeap(timers []*timer) {
- for i, t := range timers {
+func verifyTimerHeap(pp *p) {
+ for i, t := range pp.timers {
if i == 0 {
// First timer has no parent.
continue
// The heap is 4-ary. See siftupTimer and siftdownTimer.
p := (i - 1) / 4
- if t.when < timers[p].when {
- print("bad timer heap at ", i, ": ", p, ": ", timers[p].when, ", ", i, ": ", t.when, "\n")
+ if t.when < pp.timers[p].when {
+ print("bad timer heap at ", i, ": ", p, ": ", pp.timers[p].when, ", ", i, ": ", t.when, "\n")
throw("bad timer heap")
}
}
+ if numTimers := int(atomic.Load(&pp.numTimers)); len(pp.timers) != numTimers {
+ println("timer heap len", len(pp.timers), "!= numTimers", numTimers)
+ throw("bad timer heap len")
+ }
}
// updateTimer0When sets the P's timer0When field.