diff options
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/proc.go | 4 | ||||
| -rw-r--r-- | src/runtime/runtime2.go | 1 | ||||
| -rw-r--r-- | src/runtime/stack.go | 3 | ||||
| -rw-r--r-- | src/runtime/traceruntime.go | 2 | ||||
| -rw-r--r-- | src/runtime/tracestack.go | 17 |
5 files changed, 23 insertions, 4 deletions
diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 9817308430..0376f7812b 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -3307,10 +3307,10 @@ func execute(gp *g, inheritTime bool) { tryRecordGoroutineProfile(gp, nil, osyield) } - // Assign gp.m before entering _Grunning so running Gs have an - // M. + // Assign gp.m before entering _Grunning so running Gs have an M. mp.curg = gp gp.m = mp + gp.syncSafePoint = false // Clear the flag, which may have been set by morestack. casgstatus(gp, _Grunnable, _Grunning) gp.waitsince = 0 gp.preempt = false diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go index 96720846b2..49a2ba2752 100644 --- a/src/runtime/runtime2.go +++ b/src/runtime/runtime2.go @@ -466,6 +466,7 @@ type g struct { runnableTime int64 // the amount of time spent runnable, cleared when running, only used when tracking lockedm muintptr fipsIndicator uint8 + syncSafePoint bool // set if g is stopped at a synchronous safe point. runningCleanups atomic.Bool sig uint32 writebuf []byte diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 4b647976f0..a338708d76 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -1115,6 +1115,9 @@ func newstack() { shrinkstack(gp) } + // Set a flag indicated that we've been synchronously preempted. + gp.syncSafePoint = true + if gp.preemptStop { preemptPark(gp) // never returns } diff --git a/src/runtime/traceruntime.go b/src/runtime/traceruntime.go index 39adeb4c07..a2775a3427 100644 --- a/src/runtime/traceruntime.go +++ b/src/runtime/traceruntime.go @@ -457,7 +457,7 @@ func (tl traceLocker) GoPreempt() { // GoStop emits a GoStop event with the provided reason. func (tl traceLocker) GoStop(reason traceGoStopReason) { - tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) + tl.eventWriter(tracev2.GoRunning, tracev2.ProcRunning).event(tracev2.EvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(0)) } // GoPark emits a GoBlock event with the provided reason. diff --git a/src/runtime/tracestack.go b/src/runtime/tracestack.go index bca2d0a88d..2ee68c85f0 100644 --- a/src/runtime/tracestack.go +++ b/src/runtime/tracestack.go @@ -109,7 +109,22 @@ func traceStack(skip int, gp *g, gen uintptr) uint64 { nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.syscallbp), pcBuf[2:]) } else { pcBuf[1] = gp.sched.pc - nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[2:]) + if gp.syncSafePoint { + // We're stopped in morestack, which is an odd state because gp.sched.bp + // refers to our parent frame, since we haven't had the chance to push our + // frame pointer to the stack yet. If we just start walking from gp.sched.bp, + // we'll skip a frame as a result. Luckily, we can find the PC we want right + // at gp.sched.sp on non-LR platforms, and we have it directly on LR platforms. + // See issue go.dev/issue/68090. + if usesLR { + pcBuf[2] = gp.sched.lr + } else { + pcBuf[2] = *(*uintptr)(unsafe.Pointer(gp.sched.sp)) + } + nstk += 2 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[3:]) + } else { + nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[2:]) + } } } } |
