]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.16] runtime: don't clear timerModifiedEarliest if adjustTimers...
authorIan Lance Taylor <iant@golang.org>
Thu, 22 Jul 2021 02:57:56 +0000 (19:57 -0700)
committerIan Lance Taylor <iant@golang.org>
Thu, 22 Jul 2021 21:53:16 +0000 (21:53 +0000)
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 <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
(cherry picked from commit 798ec73519a7226d6d436e42498a54aed23b8468)
Reviewed-on: https://go-review.googlesource.com/c/go/+/336689

src/runtime/runtime2.go
src/runtime/time.go
src/time/sleep_test.go

index 9a032d8658c707ca28d11c6a1560ed29997cbadc..dd375da1936c5dd743b63ab17bb1dcca2688fbae 100644 (file)
@@ -653,7 +653,7 @@ type p struct {
        // timerModifiedEarlier status. Because the timer may have been
        // modified again, there need not be any timer with this value.
        // This is updated using atomic functions.
-       // This is 0 if the value is unknown.
+       // This is 0 if there are no timerModifiedEarlier timers.
        timerModifiedEarliest uint64
 
        // Per-P GC state
index dee6a674e4cdd277a9924abe27dfd1a389ba5759..7b84d2af571515e6e37d442ec57fbeba2a06321b 100644 (file)
@@ -668,11 +668,6 @@ func adjusttimers(pp *p, now int64) {
                if verifyTimers {
                        verifyTimerHeap(pp)
                }
-               // There are no timers to adjust, so it is safe to clear
-               // timerModifiedEarliest. Do so in case it is stale.
-               // Everything will work if we don't do this,
-               // but clearing here may save future calls to adjusttimers.
-               atomic.Store64(&pp.timerModifiedEarliest, 0)
                return
        }
 
index 6ee0631a85564680bf91df0bc8e9d0ab0f3437a2..e0172bf5e0b7361891b6fcbef8c5db35460af763 100644 (file)
@@ -527,6 +527,40 @@ func TestZeroTimer(t *testing.T) {
        }
 }
 
+// Test that rapidly moving a timer earlier doesn't cause it to get dropped.
+// Issue 47329.
+func TestTimerModifiedEarlier(t *testing.T) {
+       past := Until(Unix(0, 0))
+       count := 1000
+       fail := 0
+       for i := 0; i < count; i++ {
+               timer := NewTimer(Hour)
+               for j := 0; j < 10; j++ {
+                       if !timer.Stop() {
+                               <-timer.C
+                       }
+                       timer.Reset(past)
+               }
+
+               deadline := NewTimer(10 * Second)
+               defer deadline.Stop()
+               now := Now()
+               select {
+               case <-timer.C:
+                       if since := Since(now); since > 8*Second {
+                               t.Errorf("timer took too long (%v)", since)
+                               fail++
+                       }
+               case <-deadline.C:
+                       t.Error("deadline expired")
+               }
+       }
+
+       if fail > 0 {
+               t.Errorf("%d failures", fail)
+       }
+}
+
 // Benchmark timer latency when the thread that creates the timer is busy with
 // other work and the timers must be serviced by other threads.
 // https://golang.org/issue/38860