aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/time.go26
1 files changed, 20 insertions, 6 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 96b7b76b07..42f629d168 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -239,12 +239,8 @@ func (t *timer) updateHeap(ts *timers) (updated bool) {
assertLockHeld(&ts.mu)
}
if t.state&timerZombie != 0 {
- // Take timer out of heap, applying final t.whenHeap update first.
- t.state &^= timerHeaped | timerZombie
- if t.state&timerModified != 0 {
- t.state &^= timerModified
- t.whenHeap = t.when
- }
+ // Take timer out of heap.
+ t.state &^= timerHeaped | timerZombie | timerModified
if ts != nil {
ts.zombies.Add(-1)
ts.deleteMin()
@@ -651,6 +647,24 @@ func (ts *timers) cleanHead() {
return
}
+ // Delete zombies from tail of heap. It requires no heap adjustments at all,
+ // and doing so increases the chances that when we swap out a zombie
+ // in heap[0] for the tail of the heap, we'll get a non-zombie timer,
+ // shortening this loop.
+ n := len(ts.heap)
+ if t := ts.heap[n-1]; t.astate.Load()&timerZombie != 0 {
+ t.lock()
+ if t.state&timerZombie != 0 {
+ t.state &^= timerHeaped | timerZombie | timerModified
+ t.ts = nil
+ ts.zombies.Add(-1)
+ ts.heap[n-1] = nil
+ ts.heap = ts.heap[:n-1]
+ }
+ t.unlock()
+ continue
+ }
+
t := ts.heap[0]
if t.ts != ts {
throw("bad ts")