http2: fix race condition when disabling goroutine debugging for one test
Fixes golang/go#66519
Change-Id: I7aecf20db44caaaf49754d62db193b8c42f3c63a
Reviewed-on: https://go-review.googlesource.com/c/net/+/701836
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
diff --git a/http2/gotrack.go b/http2/gotrack.go
index 9933c9f..9921ca0 100644
--- a/http2/gotrack.go
+++ b/http2/gotrack.go
@@ -15,21 +15,32 @@
"runtime"
"strconv"
"sync"
+ "sync/atomic"
)
var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
+// Setting DebugGoroutines to false during a test to disable goroutine debugging
+// results in race detector complaints when a test leaves goroutines running before
+// returning. Tests shouldn't do this, of course, but when they do it generally shows
+// up as infrequent, hard-to-debug flakes. (See #66519.)
+//
+// Disable goroutine debugging during individual tests with an atomic bool.
+// (Note that it's safe to enable/disable debugging mid-test, so the actual race condition
+// here is harmless.)
+var disableDebugGoroutines atomic.Bool
+
type goroutineLock uint64
func newGoroutineLock() goroutineLock {
- if !DebugGoroutines {
+ if !DebugGoroutines || disableDebugGoroutines.Load() {
return 0
}
return goroutineLock(curGoroutineID())
}
func (g goroutineLock) check() {
- if !DebugGoroutines {
+ if !DebugGoroutines || disableDebugGoroutines.Load() {
return
}
if curGoroutineID() != uint64(g) {
@@ -38,7 +49,7 @@
}
func (g goroutineLock) checkNotOn() {
- if !DebugGoroutines {
+ if !DebugGoroutines || disableDebugGoroutines.Load() {
return
}
if curGoroutineID() == uint64(g) {
diff --git a/http2/server_test.go b/http2/server_test.go
index af1ebe0..71287d1 100644
--- a/http2/server_test.go
+++ b/http2/server_test.go
@@ -3520,9 +3520,10 @@
}
func disableGoroutineTracking(t testing.TB) {
- old := DebugGoroutines
- DebugGoroutines = false
- t.Cleanup(func() { DebugGoroutines = old })
+ disableDebugGoroutines.Store(true)
+ t.Cleanup(func() {
+ disableDebugGoroutines.Store(false)
+ })
}
func BenchmarkServer_GetRequest(b *testing.B) {