]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.17] runtime: add race annotations to metricsSema
authorMichael Pratt <mpratt@google.com>
Tue, 28 Jun 2022 19:17:12 +0000 (15:17 -0400)
committerHeschi Kreinick <heschi@google.com>
Wed, 6 Jul 2022 19:34:44 +0000 (19:34 +0000)
metricsSema protects the metrics map. The map implementation is race
instrumented regardless of which package is it called from.

semacquire/semrelease are not automatically race instrumented, so we can
trigger race false positives without manually annotating our lock
acquire and release.

See similar instrumentation on trace.shutdownSema and reflectOffs.lock.

Fixes #53589.
For #53542.

Change-Id: Ia3fd239ac860e037d09c7cb9c4ad267391e70705
Reviewed-on: https://go-review.googlesource.com/c/go/+/414517
Run-TryBot: Michael Pratt <mpratt@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
(cherry picked from commit d6481d5b9662b29453004204746945a93a6b4eb2)
Reviewed-on: https://go-review.googlesource.com/c/go/+/415196

src/runtime/export_test.go
src/runtime/metrics.go

index 03ccfe10a80fceaf5e712a990909353db27e2716..3cee4dec5754c376ac260776fa83c8fc1928b9cf 100644 (file)
@@ -321,9 +321,9 @@ func ReadMetricsSlow(memStats *MemStats, samplesp unsafe.Pointer, len, cap int)
 
        // Initialize the metrics beforehand because this could
        // allocate and skew the stats.
-       semacquire(&metricsSema)
+       metricsLock()
        initMetrics()
-       semrelease(&metricsSema)
+       metricsUnlock()
 
        systemstack(func() {
                // Read memstats first. It's going to flush
index 4af2b0aef9d25be0d7d0d00da290d3e47afddc46..922dd2f81493c6c1586998332e04dc994d470634 100644 (file)
@@ -12,9 +12,12 @@ import (
 )
 
 var (
-       // metrics is a map of runtime/metrics keys to
-       // data used by the runtime to sample each metric's
-       // value.
+       // metrics is a map of runtime/metrics keys to data used by the runtime
+       // to sample each metric's value. metricsInit indicates it has been
+       // initialized.
+       //
+       // These fields are protected by metricsSema which should be
+       // locked/unlocked with metricsLock() / metricsUnlock().
        metricsSema uint32 = 1
        metricsInit bool
        metrics     map[string]metricData
@@ -34,6 +37,23 @@ type metricData struct {
        compute func(in *statAggregate, out *metricValue)
 }
 
+func metricsLock() {
+       // Acquire the metricsSema but with handoff. Operations are typically
+       // expensive enough that queueing up goroutines and handing off between
+       // them will be noticeably better-behaved.
+       semacquire1(&metricsSema, true, 0, 0)
+       if raceenabled {
+               raceacquire(unsafe.Pointer(&metricsSema))
+       }
+}
+
+func metricsUnlock() {
+       if raceenabled {
+               racerelease(unsafe.Pointer(&metricsSema))
+       }
+       semrelease(&metricsSema)
+}
+
 // initMetrics initializes the metrics map if it hasn't been yet.
 //
 // metricsSema must be held.
@@ -546,10 +566,7 @@ func readMetrics(samplesp unsafe.Pointer, len int, cap int) {
        sl := slice{samplesp, len, cap}
        samples := *(*[]metricSample)(unsafe.Pointer(&sl))
 
-       // Acquire the metricsSema but with handoff. This operation
-       // is expensive enough that queueing up goroutines and handing
-       // off between them will be noticeably better-behaved.
-       semacquire1(&metricsSema, true, 0, 0)
+       metricsLock()
 
        // Ensure the map is initialized.
        initMetrics()
@@ -573,5 +590,5 @@ func readMetrics(samplesp unsafe.Pointer, len int, cap int) {
                data.compute(&agg, &sample.value)
        }
 
-       semrelease(&metricsSema)
+       metricsUnlock()
 }