Skip to content

Commit 24fa754

Browse files
rscgopherbot
authored andcommitted
runtime: fix spurious race using Ticker.Reset
Ticker.Reset was added in CL 217362 in 2020. It added the runtime helper modTimer, which is analogous to startTimer and resetTimer but for tickers. Unlike those, it does not contain a racerelease, which means that code synchronizing by starting a ticker will be diagnosed with a spurious race. Add racerelease to modTimer and add tests of all three racereleases (in startTimer, resetTimer, and modTimer). Also do not call time.resetTimer from elsewhere in runtime, since that function is only for package time. Use t.reset instead. For #33184. Change-Id: Ie40c1ad24911f21e81b1d3cc608cf086ff2bc83d Reviewed-on: https://go-review.googlesource.com/c/go/+/568340 Auto-Submit: Russ Cox <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent a21b275 commit 24fa754

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2011 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package race_test
6+
7+
import (
8+
"testing"
9+
"time"
10+
)
11+
12+
func TestNoRaceAfterFunc(_ *testing.T) {
13+
v := 0
14+
_ = v
15+
c := make(chan int)
16+
f := func() {
17+
v = 1
18+
c <- 0
19+
}
20+
v = 2
21+
time.AfterFunc(1, f)
22+
<-c
23+
v = 3
24+
}
25+
26+
func TestNoRaceAfterFuncReset(_ *testing.T) {
27+
v := 0
28+
_ = v
29+
c := make(chan int)
30+
f := func() {
31+
v = 1
32+
c <- 0
33+
}
34+
t := time.AfterFunc(time.Hour, f)
35+
t.Stop()
36+
v = 2
37+
t.Reset(1)
38+
<-c
39+
v = 3
40+
}
41+
42+
func TestNoRaceTimer(_ *testing.T) {
43+
v := 0
44+
_ = v
45+
c := make(chan int)
46+
f := func() {
47+
v = 1
48+
c <- 0
49+
}
50+
v = 2
51+
t := time.NewTimer(1)
52+
go func() {
53+
<-t.C
54+
f()
55+
}()
56+
<-c
57+
v = 3
58+
}
59+
60+
func TestNoRaceTimerReset(_ *testing.T) {
61+
v := 0
62+
_ = v
63+
c := make(chan int)
64+
f := func() {
65+
v = 1
66+
c <- 0
67+
}
68+
t := time.NewTimer(time.Hour)
69+
go func() {
70+
<-t.C
71+
f()
72+
}()
73+
t.Stop()
74+
v = 2
75+
t.Reset(1)
76+
<-c
77+
v = 3
78+
}
79+
80+
func TestNoRaceTicker(_ *testing.T) {
81+
v := 0
82+
_ = v
83+
c := make(chan int)
84+
f := func() {
85+
v = 1
86+
c <- 0
87+
}
88+
v = 2
89+
t := time.NewTicker(1)
90+
go func() {
91+
<-t.C
92+
f()
93+
}()
94+
<-c
95+
v = 3
96+
}
97+
98+
func TestNoRaceTickerReset(_ *testing.T) {
99+
v := 0
100+
_ = v
101+
c := make(chan int)
102+
f := func() {
103+
v = 1
104+
c <- 0
105+
}
106+
t := time.NewTicker(time.Hour)
107+
go func() {
108+
<-t.C
109+
f()
110+
}()
111+
t.Stop()
112+
v = 2
113+
t.Reset(1)
114+
<-c
115+
v = 3
116+
}

src/runtime/time.go

+3
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ func resetTimer(t *timer, when int64) bool {
295295
//
296296
//go:linkname modTimer time.modTimer
297297
func modTimer(t *timer, when, period int64) {
298+
if raceenabled {
299+
racerelease(unsafe.Pointer(t))
300+
}
298301
t.modify(when, period, t.f, t.arg, t.seq)
299302
}
300303

0 commit comments

Comments
 (0)