diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2023-07-27 19:04:04 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2023-11-09 22:34:25 +0000 |
| commit | f119abb65dbe42f6cb40db698b54be3668357934 (patch) | |
| tree | 1cb07931c9e0f488724462616283a3d7ca3cc723 /src/runtime/debugcall.go | |
| parent | e3585c67576bc1b0b161448b617eb2725e9c9d69 (diff) | |
| download | go-f119abb65dbe42f6cb40db698b54be3668357934.tar.xz | |
runtime: refactor runtime->tracer API to appear more like a lock
Currently the execution tracer synchronizes with itself using very
heavyweight operations. As a result, it's totally fine for most of the
tracer code to look like:
if traceEnabled() {
traceXXX(...)
}
However, if we want to make that synchronization more lightweight (as
issue #60773 proposes), then this is insufficient. In particular, we
need to make sure the tracer can't observe an inconsistency between g
atomicstatus and the event that would be emitted for a particular
g transition. This means making the g status change appear to happen
atomically with the corresponding trace event being written out from the
perspective of the tracer.
This requires a change in API to something more like a lock. While we're
here, we might as well make sure that trace events can *only* be emitted
while this lock is held. This change introduces such an API:
traceAcquire, which returns a value that can emit events, and
traceRelease, which requires the value that was returned by
traceAcquire. In practice, this won't be a real lock, it'll be more like
a seqlock.
For the current tracer, this API is completely overkill and the value
returned by traceAcquire basically just checks trace.enabled. But it's
necessary for the tracer described in #60773 and we can implement that
more cleanly if we do this refactoring now instead of later.
For #60773.
Change-Id: Ibb9ff5958376339fafc2b5180aef65cf2ba18646
Reviewed-on: https://go-review.googlesource.com/c/go/+/515635
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/debugcall.go')
| -rw-r--r-- | src/runtime/debugcall.go | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/src/runtime/debugcall.go b/src/runtime/debugcall.go index 98ab413ff4..5dd83063ff 100644 --- a/src/runtime/debugcall.go +++ b/src/runtime/debugcall.go @@ -166,10 +166,12 @@ func debugCallWrap(dispatch uintptr) { gp.schedlink = 0 // Park the calling goroutine. - if traceEnabled() { - traceGoPark(traceBlockDebugCall, 1) - } + trace := traceAcquire() casGToWaiting(gp, _Grunning, waitReasonDebugCall) + if trace.ok() { + trace.GoPark(traceBlockDebugCall, 1) + traceRelease(trace) + } dropg() // Directly execute the new goroutine. The debug @@ -225,19 +227,23 @@ func debugCallWrap1() { // Switch back to the calling goroutine. At some point // the scheduler will schedule us again and we'll // finish exiting. - if traceEnabled() { - traceGoSched() - } + trace := traceAcquire() casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { + trace.GoSched() + traceRelease(trace) + } dropg() lock(&sched.lock) globrunqput(gp) unlock(&sched.lock) - if traceEnabled() { - traceGoUnpark(callingG, 0) - } + trace = traceAcquire() casgstatus(callingG, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(callingG, 0) + traceRelease(trace) + } execute(callingG, true) }) } |
