1
0
mirror of https://github.com/golang/go synced 2024-09-30 16:28:32 -06:00

runtime: abstract M preemption check into a function

We check whether an M is preemptible in a surprising number of places.
Put it in one function.

For #10958, #24543.

Change-Id: I305090fdb1ea7f7a55ffe25851c1e35012d0d06c
Reviewed-on: https://go-review.googlesource.com/c/go/+/201439
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
Austin Clements 2019-10-04 18:54:00 -04:00
parent 6058603471
commit d1969015b4
4 changed files with 16 additions and 7 deletions

View File

@ -126,12 +126,12 @@ func (w *gcWork) checkPut(ptr uintptr, ptrs []uintptr) {
if debugCachedWork {
alreadyFailed := w.putGen == w.pauseGen
w.putGen = w.pauseGen
if m := getg().m; m.locks > 0 || m.mallocing != 0 || m.preemptoff != "" || m.p.ptr().status != _Prunning {
if !canPreemptM(getg().m) {
// If we were to spin, the runtime may
// deadlock: the condition above prevents
// preemption (see newstack), which could
// prevent gcMarkDone from finishing the
// ragged barrier and releasing the spin.
// deadlock. Since we can't be preempted, the
// spin could prevent gcMarkDone from
// finishing the ragged barrier, which is what
// releases us from the spin.
return
}
for atomic.Load(&gcWorkPauseGen) == w.pauseGen {

View File

@ -223,3 +223,12 @@ func resumeG(state suspendGState) {
ready(gp, 0, true)
}
}
// canPreemptM reports whether mp is in a state that is safe to preempt.
//
// It is nosplit because it has nosplit callers.
//
//go:nosplit
func canPreemptM(mp *m) bool {
return mp.locks == 0 && mp.mallocing == 0 && mp.preemptoff == "" && mp.p.ptr().status == _Prunning
}

View File

@ -2703,7 +2703,7 @@ func gosched_m(gp *g) {
// goschedguarded is a forbidden-states-avoided version of gosched_m
func goschedguarded_m(gp *g) {
if gp.m.locks != 0 || gp.m.mallocing != 0 || gp.m.preemptoff != "" || gp.m.p.ptr().status != _Prunning {
if !canPreemptM(gp.m) {
gogo(&gp.sched) // never return
}

View File

@ -975,7 +975,7 @@ func newstack() {
// it needs a lock held by the goroutine), that small preemption turns
// into a real deadlock.
if preempt {
if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning {
if !canPreemptM(thisg.m) {
// Let the goroutine keep running for now.
// gp->preempt is set, so it will be preempted next time.
gp.stackguard0 = gp.stack.lo + _StackGuard