Skip to content

Commit

Permalink
runtime: implement async scheduler preemption
Browse files Browse the repository at this point in the history
This adds signal-based preemption to preemptone.

Since STW and forEachP ultimately use preemptone, this also makes
these work with async preemption.

This also makes freezetheworld more robust so tracebacks from fatal
panics should be far less likely to report "goroutine running on other
thread; stack unavailable".

For #10958, #24543. (This doesn't fix it yet because asynchronous
preemption only works on POSIX platforms on 386 and amd64 right now.)

Change-Id: If776181dd5a9b3026a7b89a1b5266521b95a5f61
Reviewed-on: https://go-review.googlesource.com/c/go/+/201762
Run-TryBot: Austin Clements <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Cherry Zhang <[email protected]>
  • Loading branch information
aclements committed Nov 2, 2019
1 parent 62e53b7 commit 177a36a
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 3 deletions.
9 changes: 7 additions & 2 deletions src/runtime/preempt.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,11 @@ func asyncPreempt()
func asyncPreempt2() {
gp := getg()
gp.asyncSafePoint = true
mcall(preemptPark)
if gp.preemptStop {
mcall(preemptPark)
} else {
mcall(gopreempt_m)
}
gp.asyncSafePoint = false
}

Expand Down Expand Up @@ -316,7 +320,8 @@ func init() {
// wantAsyncPreempt returns whether an asynchronous preemption is
// queued for gp.
func wantAsyncPreempt(gp *g) bool {
return gp.preemptStop && readgstatus(gp)&^_Gscan == _Grunning
// Check both the G and the P.
return (gp.preempt || gp.m.p != 0 && gp.m.p.ptr().preempt) && readgstatus(gp)&^_Gscan == _Grunning
}

// isAsyncSafePoint reports whether gp at instruction PC is an
Expand Down
11 changes: 10 additions & 1 deletion src/runtime/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2487,11 +2487,13 @@ func schedule() {
}

top:
pp := _g_.m.p.ptr()
pp.preempt = false

if sched.gcwaiting != 0 {
gcstopm()
goto top
}
pp := _g_.m.p.ptr()
if pp.runSafePointFn != 0 {
runSafePointFn()
}
Expand Down Expand Up @@ -4654,6 +4656,13 @@ func preemptone(_p_ *p) bool {
// Setting gp->stackguard0 to StackPreempt folds
// preemption into the normal stack overflow check.
gp.stackguard0 = stackPreempt

// Request an async preemption of this P.
if preemptMSupported && debug.asyncpreemptoff == 0 {
_p_.preempt = true
preemptM(mp)
}

return true
}

Expand Down
4 changes: 4 additions & 0 deletions src/runtime/runtime2.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ type p struct {
// Race context used while executing timer functions.
timerRaceCtx uintptr

// preempt is set to indicate that this P should be enter the
// scheduler ASAP (regardless of what G is running on it).
preempt bool

pad cpu.CacheLinePad
}

Expand Down

0 comments on commit 177a36a

Please sign in to comment.