diff options
Diffstat (limited to 'src/runtime/proc.go')
| -rw-r--r-- | src/runtime/proc.go | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 16538098cf..52def488ff 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -2433,7 +2433,7 @@ func needm(signal bool) { sp := sys.GetCallerSP() callbackUpdateSystemStack(mp, sp, signal) - // Should mark we are already in Go now. + // We must mark that we are already in Go now. // Otherwise, we may call needm again when we get a signal, before cgocallbackg1, // which means the extram list may be empty, that will cause a deadlock. mp.isExtraInC = false @@ -2455,7 +2455,8 @@ func needm(signal bool) { // mp.curg is now a real goroutine. casgstatus(mp.curg, _Gdeadextra, _Gsyscall) sched.ngsys.Add(-1) - sched.nGsyscallNoP.Add(1) + // N.B. We do not update nGsyscallNoP, because isExtraInC threads are not + // counted as real goroutines while they're in C. if !signal { if trace.ok() { @@ -2590,7 +2591,7 @@ func dropm() { casgstatus(mp.curg, _Gsyscall, _Gdeadextra) mp.curg.preemptStop = false sched.ngsys.Add(1) - sched.nGsyscallNoP.Add(-1) + decGSyscallNoP(mp) if !mp.isExtraInSig { if trace.ok() { @@ -4732,7 +4733,7 @@ func entersyscallHandleGCWait(trace traceLocker) { if trace.ok() { trace.ProcStop(pp) } - sched.nGsyscallNoP.Add(1) + addGSyscallNoP(gp.m) // We gave up our P voluntarily. pp.gcStopTime = nanotime() pp.syscalltick++ if sched.stopwait--; sched.stopwait == 0 { @@ -4763,7 +4764,7 @@ func entersyscallblock() { gp.m.syscalltick = gp.m.p.ptr().syscalltick gp.m.p.ptr().syscalltick++ - sched.nGsyscallNoP.Add(1) + addGSyscallNoP(gp.m) // We're going to give up our P. // Leave SP around for GC and traceback. pc := sys.GetCallerPC() @@ -5001,8 +5002,8 @@ func exitsyscallTryGetP(oldp *p) *p { if oldp != nil { if thread, ok := setBlockOnExitSyscall(oldp); ok { thread.takeP() + addGSyscallNoP(thread.mp) // takeP does the opposite, but this is a net zero change. thread.resume() - sched.nGsyscallNoP.Add(-1) // takeP adds 1. return oldp } } @@ -5017,7 +5018,7 @@ func exitsyscallTryGetP(oldp *p) *p { } unlock(&sched.lock) if pp != nil { - sched.nGsyscallNoP.Add(-1) + decGSyscallNoP(getg().m) // We got a P for ourselves. return pp } } @@ -5043,7 +5044,7 @@ func exitsyscallNoP(gp *g) { trace.GoSysExit(true) traceRelease(trace) } - sched.nGsyscallNoP.Add(-1) + decGSyscallNoP(getg().m) dropg() lock(&sched.lock) var pp *p @@ -5081,6 +5082,41 @@ func exitsyscallNoP(gp *g) { schedule() // Never returns. } +// addGSyscallNoP must be called when a goroutine in a syscall loses its P. +// This function updates all relevant accounting. +// +// nosplit because it's called on the syscall paths. +// +//go:nosplit +func addGSyscallNoP(mp *m) { + // It's safe to read isExtraInC here because it's only mutated + // outside of _Gsyscall, and we know this thread is attached + // to a goroutine in _Gsyscall and blocked from exiting. + if !mp.isExtraInC { + // Increment nGsyscallNoP since we're taking away a P + // from a _Gsyscall goroutine, but only if isExtraInC + // is not set on the M. If it is, then this thread is + // back to being a full C thread, and will just inflate + // the count of not-in-go goroutines. See go.dev/issue/76435. + sched.nGsyscallNoP.Add(1) + } +} + +// decGSsyscallNoP must be called whenever a goroutine in a syscall without +// a P exits the system call. This function updates all relevant accounting. +// +// nosplit because it's called from dropm. +// +//go:nosplit +func decGSyscallNoP(mp *m) { + // Update nGsyscallNoP, but only if this is not a thread coming + // out of C. See the comment in addGSyscallNoP. This logic must match, + // to avoid unmatched increments and decrements. + if !mp.isExtraInC { + sched.nGsyscallNoP.Add(-1) + } +} + // Called from syscall package before fork. // // syscall_runtime_BeforeFork is for package syscall, @@ -6758,7 +6794,7 @@ func (s syscallingThread) releaseP(state uint32) { trace.ProcSteal(s.pp) traceRelease(trace) } - sched.nGsyscallNoP.Add(1) + addGSyscallNoP(s.mp) s.pp.syscalltick++ } |
