mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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:
parent
6058603471
commit
d1969015b4
4 changed files with 16 additions and 7 deletions
|
|
@ -126,12 +126,12 @@ func (w *gcWork) checkPut(ptr uintptr, ptrs []uintptr) {
|
||||||
if debugCachedWork {
|
if debugCachedWork {
|
||||||
alreadyFailed := w.putGen == w.pauseGen
|
alreadyFailed := w.putGen == w.pauseGen
|
||||||
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
|
// If we were to spin, the runtime may
|
||||||
// deadlock: the condition above prevents
|
// deadlock. Since we can't be preempted, the
|
||||||
// preemption (see newstack), which could
|
// spin could prevent gcMarkDone from
|
||||||
// prevent gcMarkDone from finishing the
|
// finishing the ragged barrier, which is what
|
||||||
// ragged barrier and releasing the spin.
|
// releases us from the spin.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for atomic.Load(&gcWorkPauseGen) == w.pauseGen {
|
for atomic.Load(&gcWorkPauseGen) == w.pauseGen {
|
||||||
|
|
|
||||||
|
|
@ -223,3 +223,12 @@ func resumeG(state suspendGState) {
|
||||||
ready(gp, 0, true)
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2703,7 +2703,7 @@ func gosched_m(gp *g) {
|
||||||
// goschedguarded is a forbidden-states-avoided version of gosched_m
|
// goschedguarded is a forbidden-states-avoided version of gosched_m
|
||||||
func goschedguarded_m(gp *g) {
|
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
|
gogo(&gp.sched) // never return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -975,7 +975,7 @@ func newstack() {
|
||||||
// it needs a lock held by the goroutine), that small preemption turns
|
// it needs a lock held by the goroutine), that small preemption turns
|
||||||
// into a real deadlock.
|
// into a real deadlock.
|
||||||
if preempt {
|
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.
|
// Let the goroutine keep running for now.
|
||||||
// gp->preempt is set, so it will be preempted next time.
|
// gp->preempt is set, so it will be preempted next time.
|
||||||
gp.stackguard0 = gp.stack.lo + _StackGuard
|
gp.stackguard0 = gp.stack.lo + _StackGuard
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue