Skip to content

Commit 177a36a

Browse files
committed
runtime: implement async scheduler preemption
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]>
1 parent 62e53b7 commit 177a36a

File tree

3 files changed

+21
-3
lines changed

3 files changed

+21
-3
lines changed

src/runtime/preempt.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,11 @@ func asyncPreempt()
282282
func asyncPreempt2() {
283283
gp := getg()
284284
gp.asyncSafePoint = true
285-
mcall(preemptPark)
285+
if gp.preemptStop {
286+
mcall(preemptPark)
287+
} else {
288+
mcall(gopreempt_m)
289+
}
286290
gp.asyncSafePoint = false
287291
}
288292

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

322327
// isAsyncSafePoint reports whether gp at instruction PC is an

src/runtime/proc.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2487,11 +2487,13 @@ func schedule() {
24872487
}
24882488

24892489
top:
2490+
pp := _g_.m.p.ptr()
2491+
pp.preempt = false
2492+
24902493
if sched.gcwaiting != 0 {
24912494
gcstopm()
24922495
goto top
24932496
}
2494-
pp := _g_.m.p.ptr()
24952497
if pp.runSafePointFn != 0 {
24962498
runSafePointFn()
24972499
}
@@ -4654,6 +4656,13 @@ func preemptone(_p_ *p) bool {
46544656
// Setting gp->stackguard0 to StackPreempt folds
46554657
// preemption into the normal stack overflow check.
46564658
gp.stackguard0 = stackPreempt
4659+
4660+
// Request an async preemption of this P.
4661+
if preemptMSupported && debug.asyncpreemptoff == 0 {
4662+
_p_.preempt = true
4663+
preemptM(mp)
4664+
}
4665+
46574666
return true
46584667
}
46594668

src/runtime/runtime2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ type p struct {
642642
// Race context used while executing timer functions.
643643
timerRaceCtx uintptr
644644

645+
// preempt is set to indicate that this P should be enter the
646+
// scheduler ASAP (regardless of what G is running on it).
647+
preempt bool
648+
645649
pad cpu.CacheLinePad
646650
}
647651

0 commit comments

Comments
 (0)