runtime: don't hold trace.lock over semrelease in readTrace0

semrelease may unblock a goroutine, but the act of unblocking a
goroutine may emit an event, which in turn may try to acquire trace.lock
again.

It's safe to release trace.lock in readTrace0 for this because all of
the state (one variable) it uses under the lock will be recomputed when
it reacquires the lock. There's also no other synchronization
requirement to hold trace.lock. This is just a mistake.

Change-Id: Iff6c6b02efa298ebed8e60cdf6539ec161d5ec48
Reviewed-on: https://go-review.googlesource.com/c/go/+/544178
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Michael Anthony Knyszek 2023-11-21 23:24:59 +00:00 committed by Michael Knyszek
parent 5249947f11
commit e4ea6283e4
1 changed files with 6 additions and 1 deletions

View File

@ -764,6 +764,8 @@ func readTrace0() (buf []byte, park bool) {
// can continue to advance.
if trace.flushedGen.Load() == gen {
if trace.shutdown.Load() {
unlock(&trace.lock)
// Wake up anyone waiting for us to be done with this generation.
//
// Do this after reading trace.shutdown, because the thread we're
@ -778,13 +780,13 @@ func readTrace0() (buf []byte, park bool) {
// We're shutting down, and the last generation is fully
// read. We're done.
unlock(&trace.lock)
return nil, false
}
// The previous gen has had all of its buffers flushed, and
// there's nothing else for us to read. Advance the generation
// we're reading from and try again.
trace.readerGen.Store(trace.gen.Load())
unlock(&trace.lock)
// Wake up anyone waiting for us to be done with this generation.
//
@ -795,6 +797,9 @@ func readTrace0() (buf []byte, park bool) {
racerelease(unsafe.Pointer(&trace.doneSema[gen%2]))
}
semrelease(&trace.doneSema[gen%2])
// Reacquire the lock and go back to the top of the loop.
lock(&trace.lock)
continue
}
// Wait for new data.