lock(&pp.timersLock)
if len(pp.timers) > 0 {
- adjusttimers(pp, now)
+ // If this is the local P, and there are a lot of deleted timers,
+ // clear them out. We only do this for the local P to reduce
+ // lock contention on timersLock.
+ force := pp == getg().m.p.ptr() && int(pp.deletedTimers.Load()) > len(pp.timers)/4
+ adjusttimers(pp, now, force)
for len(pp.timers) > 0 {
// Note that runtimer may temporarily unlock
// pp.timersLock.
}
}
- // If this is the local P, and there are a lot of deleted timers,
- // clear them out. We only do this for the local P to reduce
- // lock contention on timersLock.
- if pp == getg().m.p.ptr() && int(pp.deletedTimers.Load()) > len(pp.timers)/4 {
- clearDeletedTimers(pp)
- }
-
unlock(&pp.timersLock)
return now, pollUntil, ran
// timerMoving -> wait until status changes
// timerRemoving -> wait until status changes
// timerModifying -> wait until status changes
-// cleantimers (looks in P's timer heap):
-// timerDeleted -> timerRemoving -> timerRemoved
-// timerModifiedXX -> timerMoving -> timerWaiting
// adjusttimers (looks in P's timer heap):
// timerDeleted -> timerRemoving -> timerRemoved
// timerModifiedXX -> timerMoving -> timerWaiting
// the correct place in the heap. While looking for those timers,
// it also moves timers that have been modified to run later,
// and removes deleted timers. The caller must have locked the timers for pp.
-func adjusttimers(pp *p, now int64) {
+func adjusttimers(pp *p, now int64, force bool) {
// If we haven't yet reached the time of the first timerModifiedEarlier
// timer, don't do anything. This speeds up programs that adjust
// a lot of timers back and forth if the timers rarely expire.
// We'll postpone looking through all the adjusted timers until
// one would actually expire.
- first := pp.timerModifiedEarliest.Load()
- if first == 0 || first > now {
- if verifyTimers {
- verifyTimerHeap(pp)
+ if !force {
+ first := pp.timerModifiedEarliest.Load()
+ if first == 0 || first > now {
+ if verifyTimers {
+ verifyTimerHeap(pp)
+ }
+ return
}
- return
}
// We are going to clear all timerModifiedEarlier timers.
}
}
-// clearDeletedTimers removes all deleted timers from the P's timer heap.
-// This is used to avoid clogging up the heap if the program
-// starts a lot of long-running timers and then stops them.
-// For example, this can happen via context.WithTimeout.
-//
-// This is the only function that walks through the entire timer heap,
-// other than moveTimers which only runs when the world is stopped.
-//
-// The caller must have locked the timers for pp.
-func clearDeletedTimers(pp *p) {
- // We are going to clear all timerModifiedEarlier timers.
- // Do this now in case new ones show up while we are looping.
- pp.timerModifiedEarliest.Store(0)
-
- cdel := int32(0)
- to := 0
- changedHeap := false
- timers := pp.timers
-nextTimer:
- for _, t := range timers {
- for {
- switch s := t.status.Load(); s {
- case timerWaiting:
- if changedHeap {
- timers[to] = t
- siftupTimer(timers, to)
- }
- to++
- continue nextTimer
- case timerModifiedEarlier, timerModifiedLater:
- if t.status.CompareAndSwap(s, timerMoving) {
- t.when = t.nextwhen
- timers[to] = t
- siftupTimer(timers, to)
- to++
- changedHeap = true
- if !t.status.CompareAndSwap(timerMoving, timerWaiting) {
- badTimer()
- }
- continue nextTimer
- }
- case timerDeleted:
- if t.status.CompareAndSwap(s, timerRemoving) {
- t.pp = 0
- cdel++
- if !t.status.CompareAndSwap(timerRemoving, timerRemoved) {
- badTimer()
- }
- changedHeap = true
- continue nextTimer
- }
- case timerModifying:
- // Loop until modification complete.
- osyield()
- case timerNoStatus, timerRemoved:
- // We should not see these status values in a timer heap.
- badTimer()
- case timerRunning, timerRemoving, timerMoving:
- // Some other P thinks it owns this timer,
- // which should not happen.
- badTimer()
- default:
- badTimer()
- }
- }
- }
-
- // Set remaining slots in timers slice to nil,
- // so that the timer values can be garbage collected.
- for i := to; i < len(timers); i++ {
- timers[i] = nil
- }
-
- pp.deletedTimers.Add(-cdel)
- pp.numTimers.Add(-cdel)
-
- 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.