From: Russ Cox Date: Fri, 1 Mar 2024 01:14:32 +0000 (-0500) Subject: runtime: fix spurious race using Ticker.Reset X-Git-Tag: go1.23rc1~940 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=24fa7544b08f998ed3dd857342dc7787924276a1;p=gostls13.git 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 LUCI-TryBot-Result: Go LUCI Reviewed-by: Michael Pratt --- diff --git a/src/runtime/race/testdata/time_test.go b/src/runtime/race/testdata/time_test.go new file mode 100644 index 0000000000..820d7c4708 --- /dev/null +++ b/src/runtime/race/testdata/time_test.go @@ -0,0 +1,116 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package race_test + +import ( + "testing" + "time" +) + +func TestNoRaceAfterFunc(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + v = 2 + time.AfterFunc(1, f) + <-c + v = 3 +} + +func TestNoRaceAfterFuncReset(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + t := time.AfterFunc(time.Hour, f) + t.Stop() + v = 2 + t.Reset(1) + <-c + v = 3 +} + +func TestNoRaceTimer(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + v = 2 + t := time.NewTimer(1) + go func() { + <-t.C + f() + }() + <-c + v = 3 +} + +func TestNoRaceTimerReset(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + t := time.NewTimer(time.Hour) + go func() { + <-t.C + f() + }() + t.Stop() + v = 2 + t.Reset(1) + <-c + v = 3 +} + +func TestNoRaceTicker(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + v = 2 + t := time.NewTicker(1) + go func() { + <-t.C + f() + }() + <-c + v = 3 +} + +func TestNoRaceTickerReset(_ *testing.T) { + v := 0 + _ = v + c := make(chan int) + f := func() { + v = 1 + c <- 0 + } + t := time.NewTicker(time.Hour) + go func() { + <-t.C + f() + }() + t.Stop() + v = 2 + t.Reset(1) + <-c + v = 3 +} diff --git a/src/runtime/time.go b/src/runtime/time.go index b509d99b80..cee0197907 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -295,6 +295,9 @@ func resetTimer(t *timer, when int64) bool { // //go:linkname modTimer time.modTimer func modTimer(t *timer, when, period int64) { + if raceenabled { + racerelease(unsafe.Pointer(t)) + } t.modify(when, period, t.f, t.arg, t.seq) }