aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/time.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/time.go')
-rw-r--r--src/runtime/time.go38
1 files changed, 29 insertions, 9 deletions
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 711f3e472d..a1f8351a1e 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -62,6 +62,7 @@ type timer struct {
isFake bool // timer is using fake time; immutable; can be read without lock
blocked uint32 // number of goroutines blocked on timer's channel
+ rand uint32 // randomizes order of timers at same instant; only set when isFake
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
// each time calling f(arg, seq, delay) in the timer goroutine, so f must be
@@ -165,6 +166,21 @@ type timerWhen struct {
when int64
}
+// less reports whether tw is less than other.
+func (tw timerWhen) less(other timerWhen) bool {
+ switch {
+ case tw.when < other.when:
+ return true
+ case tw.when > other.when:
+ return false
+ default:
+ // When timers wake at the same time, use a per-timer random value to order them.
+ // We only set the random value for timers using fake time, since there's
+ // no practical way to schedule real-time timers for the same instant.
+ return tw.timer.rand < other.timer.rand
+ }
+}
+
func (ts *timers) lock() {
lock(&ts.mu)
}
@@ -696,6 +712,12 @@ func (t *timer) maybeAdd() {
when := int64(0)
wake := false
if t.needsAdd() {
+ if t.isFake {
+ // Re-randomize timer order.
+ // We could do this for all timers, but unbubbled timers are highly
+ // unlikely to have the same when.
+ t.rand = cheaprand()
+ }
t.state |= timerHeaped
when = t.when
wakeTime := ts.wakeTime()
@@ -1234,7 +1256,7 @@ func (ts *timers) verify() {
// The heap is timerHeapN-ary. See siftupTimer and siftdownTimer.
p := int(uint(i-1) / timerHeapN)
- if tw.when < ts.heap[p].when {
+ if tw.less(ts.heap[p]) {
print("bad timer heap at ", i, ": ", p, ": ", ts.heap[p].when, ", ", i, ": ", tw.when, "\n")
throw("bad timer heap")
}
@@ -1312,13 +1334,12 @@ func (ts *timers) siftUp(i int) {
badTimer()
}
tw := heap[i]
- when := tw.when
- if when <= 0 {
+ if tw.when <= 0 {
badTimer()
}
for i > 0 {
p := int(uint(i-1) / timerHeapN) // parent
- if when >= heap[p].when {
+ if !tw.less(heap[p]) {
break
}
heap[i] = heap[p]
@@ -1341,8 +1362,7 @@ func (ts *timers) siftDown(i int) {
return
}
tw := heap[i]
- when := tw.when
- if when <= 0 {
+ if tw.when <= 0 {
badTimer()
}
for {
@@ -1350,11 +1370,11 @@ func (ts *timers) siftDown(i int) {
if leftChild >= n {
break
}
- w := when
+ w := tw
c := -1
for j, tw := range heap[leftChild:min(leftChild+timerHeapN, n)] {
- if tw.when < w {
- w = tw.when
+ if tw.less(w) {
+ w = tw
c = leftChild + j
}
}