From 94f4686a77d1d708f240eac388fb5c5b83e2c15f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 2 Dec 2019 12:07:22 -0800 Subject: [PATCH] runtime: use current P's race context in timer code We were using the race context of the P that held the timer, but since we unlock the P's timers while executing a timer that could lead to a race on the race context itself. Updates #6239 Updates #27707 Fixes #35906 Change-Id: I5f9d5f52d8e28dffb88c3327301071b16ed1a913 Reviewed-on: https://go-review.googlesource.com/c/go/+/209580 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall Reviewed-by: Michael Knyszek --- src/runtime/race/timer_test.go | 33 +++++++++++++++++++++++++++++++++ src/runtime/time.go | 11 ++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/runtime/race/timer_test.go diff --git a/src/runtime/race/timer_test.go b/src/runtime/race/timer_test.go new file mode 100644 index 0000000000..a6c34a8352 --- /dev/null +++ b/src/runtime/race/timer_test.go @@ -0,0 +1,33 @@ +// Copyright 2019 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. + +// +build race + +package race_test + +import ( + "sync" + "testing" + "time" +) + +func TestTimers(t *testing.T) { + const goroutines = 8 + var wg sync.WaitGroup + wg.Add(goroutines) + var mu sync.Mutex + for i := 0; i < goroutines; i++ { + go func() { + defer wg.Done() + ticker := time.NewTicker(1) + defer ticker.Stop() + for c := 0; c < 1000; c++ { + <-ticker.C + mu.Lock() + mu.Unlock() + } + }() + } + wg.Wait() +} diff --git a/src/runtime/time.go b/src/runtime/time.go index a7d14cf877..d64bea814f 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -805,10 +805,11 @@ func runtimer(pp *p, now int64) int64 { //go:systemstack func runOneTimer(pp *p, t *timer, now int64) { if raceenabled { - if pp.timerRaceCtx == 0 { - pp.timerRaceCtx = racegostart(funcPC(runtimer) + sys.PCQuantum) + ppcur := getg().m.p.ptr() + if ppcur.timerRaceCtx == 0 { + ppcur.timerRaceCtx = racegostart(funcPC(runtimer) + sys.PCQuantum) } - raceacquirectx(pp.timerRaceCtx, unsafe.Pointer(t)) + raceacquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t)) } f := t.f @@ -836,12 +837,12 @@ func runOneTimer(pp *p, t *timer, now int64) { } if raceenabled { - // Temporarily use the P's racectx for g0. + // Temporarily use the current P's racectx for g0. gp := getg() if gp.racectx != 0 { throw("runOneTimer: unexpected racectx") } - gp.racectx = pp.timerRaceCtx + gp.racectx = gp.m.p.ptr().timerRaceCtx } unlock(&pp.timersLock) -- 2.50.0