summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/runtime/proc.go5
-rw-r--r--src/runtime/trace.go25
2 files changed, 21 insertions, 9 deletions
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 363e8befe6..fd892115bf 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1999,7 +1999,6 @@ func oneNewExtraM() {
mp.lockedg.set(gp)
gp.lockedm.set(mp)
gp.goid = sched.goidgen.Add(1)
- gp.trace.sysBlockTraced = true
if raceenabled {
gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum)
}
@@ -2705,7 +2704,7 @@ func execute(gp *g, inheritTime bool) {
if traceEnabled() {
// GoSysExit has to happen when we have a P, but before GoStart.
// So we emit it here.
- if gp.syscallsp != 0 && gp.trace.sysBlockTraced {
+ if gp.syscallsp != 0 {
traceGoSysExit()
}
traceGoStart()
@@ -3856,7 +3855,6 @@ func reentersyscall(pc, sp uintptr) {
}
gp.m.syscalltick = gp.m.p.ptr().syscalltick
- gp.trace.sysBlockTraced = true
pp := gp.m.p.ptr()
pp.m = 0
gp.m.oldp.set(pp)
@@ -3917,7 +3915,6 @@ func entersyscallblock() {
gp.throwsplit = true
gp.stackguard0 = stackPreempt // see comment in entersyscall
gp.m.syscalltick = gp.m.p.ptr().syscalltick
- gp.trace.sysBlockTraced = true
gp.m.p.ptr().syscalltick++
// Leave SP around for GC and traceback.
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 9c7792d42b..45a066e7a2 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -163,10 +163,10 @@ var trace struct {
// gTraceState is per-G state for the tracer.
type gTraceState struct {
- sysExitTicks int64 // cputicks when syscall has returned
- sysBlockTraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
- seq uint64 // trace event sequencer
- lastP puintptr // last P emitted an event for this goroutine
+ sysExitTicks int64 // cputicks when syscall has returned
+ tracedSyscallEnter bool // syscall or cgo was entered while trace was enabled or StartTrace has emitted EvGoInSyscall about this goroutine
+ seq uint64 // trace event sequencer
+ lastP puintptr // last P emitted an event for this goroutine
}
// mTraceState is per-M state for the tracer.
@@ -309,6 +309,7 @@ func StartTrace() error {
}
if status == _Gsyscall {
gp.trace.seq++
+ gp.trace.tracedSyscallEnter = true
traceEvent(traceEvGoInSyscall, -1, gp.goid)
} else if status == _Gdead && gp.m != nil && gp.m.isextra {
// Trigger two trace events for the dead g in the extra m,
@@ -320,9 +321,16 @@ func StartTrace() error {
id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(0) + sys.PCQuantum}) // no start pc
traceEvent(traceEvGoCreate, -1, gp.goid, uint64(id), stackID)
gp.trace.seq++
+ gp.trace.tracedSyscallEnter = true
traceEvent(traceEvGoInSyscall, -1, gp.goid)
} else {
- gp.trace.sysBlockTraced = false
+ // We need to explicitly clear the flag. A previous trace might have ended with a goroutine
+ // not emitting a GoSysExit and clearing the flag, leaving it in a stale state. Clearing
+ // it here makes it unambiguous to any goroutine exiting a syscall racing with us that
+ // no EvGoInSyscall event was emitted for it. (It's not racy to set this flag here, because
+ // it'll only get checked when the goroutine runs again, which will be after the world starts
+ // again.)
+ gp.trace.tracedSyscallEnter = false
}
})
traceProcStart()
@@ -1603,11 +1611,18 @@ func traceGoSysCall() {
// Skip the extra trampoline frame used on most systems.
skip = 4
}
+ getg().m.curg.trace.tracedSyscallEnter = true
traceEvent(traceEvGoSysCall, skip)
}
func traceGoSysExit() {
gp := getg().m.curg
+ if !gp.trace.tracedSyscallEnter {
+ // There was no syscall entry traced for us at all, so there's definitely
+ // no EvGoSysBlock or EvGoInSyscall before us, which EvGoSysExit requires.
+ return
+ }
+ gp.trace.tracedSyscallEnter = false
ts := gp.trace.sysExitTicks
if ts != 0 && ts < trace.ticksStart {
// There is a race between the code that initializes sysExitTicks