runtime: always run semacquire on the G stack

semacquire might need to park the currently running G.  It can
only park if called from the G stack (because it has no way of
saving the M stack state).  So all calls to semacquire must come
from the G stack.

The three violators are GOMAXPROCS, ReadMemStats, and WriteHeapDump.
This change moves the semacquire call earlier, out of their C code
and into their Go code.

This seldom caused bugs because semacquire seldom actually had
to park the caller.  But it did happen intermittently.

Fixes #8749

LGTM=dvyukov
R=golang-codereviews, dvyukov, bradfitz
CC=golang-codereviews
https://golang.org/cl/144940043
This commit is contained in:
Keith Randall 2014-09-16 17:26:16 -07:00
parent e28746c444
commit da8cf5438a
9 changed files with 114 additions and 132 deletions

View file

@ -24,15 +24,29 @@ func UnlockOSThread()
// The number of logical CPUs on the local machine can be queried with NumCPU.
// This call will go away when the scheduler improves.
func GOMAXPROCS(n int) int {
g := getg()
g.m.scalararg[0] = uintptr(n)
onM(gomaxprocs_m)
n = int(g.m.scalararg[0])
g.m.scalararg[0] = 0
return n
}
if n > _MaxGomaxprocs {
n = _MaxGomaxprocs
}
lock(&sched.lock)
ret := int(gomaxprocs)
unlock(&sched.lock)
if n <= 0 || n == ret {
return ret
}
func gomaxprocs_m() // proc.c
semacquire(&worldsema, false)
gp := getg()
gp.m.gcing = 1
onM(stoptheworld)
// newprocs will be processed by starttheworld
newprocs = int32(n)
gp.m.gcing = 0
semrelease(&worldsema)
onM(starttheworld)
return ret
}
// NumCPU returns the number of logical CPUs on the local machine.
func NumCPU() int {