diff options
Diffstat (limited to 'src/runtime/preempt.go')
| -rw-r--r-- | src/runtime/preempt.go | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/src/runtime/preempt.go b/src/runtime/preempt.go index 82d85cd707..aedf7f3ff5 100644 --- a/src/runtime/preempt.go +++ b/src/runtime/preempt.go @@ -359,7 +359,11 @@ func wantAsyncPreempt(gp *g) bool { // In some cases the PC is safe for asynchronous preemption but it // also needs to adjust the resumption PC. The new PC is returned in // the second result. -func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { +// +// If noResume is true, we know we're not going to resume execution +// on this goroutine (as we're crashing), and thus we can preempt +// more aggressively. +func isAsyncSafePoint(gp *g, pc, sp, lr uintptr, noResume bool) (bool, uintptr) { mp := gp.m // Only user Gs can have safe-points. We check this first @@ -370,7 +374,7 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { } // Check M state. - if mp.p == 0 || !canPreemptM(mp) { + if mp.p == 0 || (!canPreemptM(mp) && !noResume) { return false, 0 } @@ -385,6 +389,13 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { // Not Go code. return false, 0 } + if noResume && f.flag&abi.FuncFlagAsm == 0 { + // We're not going to resume execution and not going to scan the + // stack for GC, so we don't care whether it is a safe point, and + // also don't care the resumption PC. + // TODO: maybe we can preempt non-SPWRITE assembly functions? + return true, pc + } if (GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "mips64" || GOARCH == "mips64le") && lr == pc+8 && funcspdelta(f, pc) == 0 { // We probably stopped at a half-executed CALL instruction, // where the LR is updated but the PC has not. If we preempt |
