Skip to content

Commit ed8cbbc

Browse files
[release-branch.go1.16] runtime: don't clear timerModifiedEarliest if adjustTimers is 0
This avoids a race when a new timerModifiedEarlier timer is created by a different goroutine. For #47329 Fixes #47332 Change-Id: I6f6c87b4a9b5491b201c725c10bc98e23e0ed9d1 Reviewed-on: https://go-review.googlesource.com/c/go/+/336432 Trust: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> (cherry picked from commit 798ec73) Reviewed-on: https://go-review.googlesource.com/c/go/+/336689
1 parent bc51e93 commit ed8cbbc

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

src/runtime/runtime2.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ type p struct {
653653
// timerModifiedEarlier status. Because the timer may have been
654654
// modified again, there need not be any timer with this value.
655655
// This is updated using atomic functions.
656-
// This is 0 if the value is unknown.
656+
// This is 0 if there are no timerModifiedEarlier timers.
657657
timerModifiedEarliest uint64
658658

659659
// Per-P GC state

src/runtime/time.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -668,11 +668,6 @@ func adjusttimers(pp *p, now int64) {
668668
if verifyTimers {
669669
verifyTimerHeap(pp)
670670
}
671-
// There are no timers to adjust, so it is safe to clear
672-
// timerModifiedEarliest. Do so in case it is stale.
673-
// Everything will work if we don't do this,
674-
// but clearing here may save future calls to adjusttimers.
675-
atomic.Store64(&pp.timerModifiedEarliest, 0)
676671
return
677672
}
678673

src/time/sleep_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,40 @@ func TestZeroTimer(t *testing.T) {
527527
}
528528
}
529529

530+
// Test that rapidly moving a timer earlier doesn't cause it to get dropped.
531+
// Issue 47329.
532+
func TestTimerModifiedEarlier(t *testing.T) {
533+
past := Until(Unix(0, 0))
534+
count := 1000
535+
fail := 0
536+
for i := 0; i < count; i++ {
537+
timer := NewTimer(Hour)
538+
for j := 0; j < 10; j++ {
539+
if !timer.Stop() {
540+
<-timer.C
541+
}
542+
timer.Reset(past)
543+
}
544+
545+
deadline := NewTimer(10 * Second)
546+
defer deadline.Stop()
547+
now := Now()
548+
select {
549+
case <-timer.C:
550+
if since := Since(now); since > 8*Second {
551+
t.Errorf("timer took too long (%v)", since)
552+
fail++
553+
}
554+
case <-deadline.C:
555+
t.Error("deadline expired")
556+
}
557+
}
558+
559+
if fail > 0 {
560+
t.Errorf("%d failures", fail)
561+
}
562+
}
563+
530564
// Benchmark timer latency when the thread that creates the timer is busy with
531565
// other work and the timers must be serviced by other threads.
532566
// https://golang.org/issue/38860

0 commit comments

Comments
 (0)