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)
}
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()
}
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)
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.
// 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.
}
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,
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()
// 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