summaryrefslogtreecommitdiff
path: root/src/runtime/panic.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go40
1 files changed, 22 insertions, 18 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 121f2022a4..3783e3dede 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -1190,7 +1190,7 @@ func fatalpanic(msgs *_panic) {
//
//go:nowritebarrierrec
func startpanic_m() bool {
- _g_ := getg()
+ gp := getg()
if mheap_.cachealloc.size == 0 { // very early
print("runtime: panic before malloc heap initialized\n")
}
@@ -1198,18 +1198,18 @@ func startpanic_m() bool {
// could happen in a signal handler, or in a throw, or inside
// malloc itself. We want to catch if an allocation ever does
// happen (even if we're not in one of these situations).
- _g_.m.mallocing++
+ gp.m.mallocing++
// If we're dying because of a bad lock count, set it to a
// good lock count so we don't recursively panic below.
- if _g_.m.locks < 0 {
- _g_.m.locks = 1
+ if gp.m.locks < 0 {
+ gp.m.locks = 1
}
- switch _g_.m.dying {
+ switch gp.m.dying {
case 0:
// Setting dying >0 has the side-effect of disabling this G's writebuf.
- _g_.m.dying = 1
+ gp.m.dying = 1
atomic.Xadd(&panicking, 1)
lock(&paniclk)
if debug.schedtrace > 0 || debug.scheddetail > 0 {
@@ -1220,13 +1220,13 @@ func startpanic_m() bool {
case 1:
// Something failed while panicking.
// Just print a stack trace and exit.
- _g_.m.dying = 2
+ gp.m.dying = 2
print("panic during panic\n")
return false
case 2:
// This is a genuine bug in the runtime, we couldn't even
// print the stack trace successfully.
- _g_.m.dying = 3
+ gp.m.dying = 3
print("stack trace unavailable\n")
exit(4)
fallthrough
@@ -1240,6 +1240,8 @@ func startpanic_m() bool {
var didothers bool
var deadlock mutex
+// gp is the crashing g running on this M, but may be a user G, while getg() is
+// always g0.
func dopanic_m(gp *g, pc, sp uintptr) bool {
if gp.sig != 0 {
signame := signame(gp.sig)
@@ -1252,7 +1254,6 @@ func dopanic_m(gp *g, pc, sp uintptr) bool {
}
level, all, docrash := gotraceback()
- _g_ := getg()
if level > 0 {
if gp != gp.m.curg {
all = true
@@ -1261,7 +1262,7 @@ func dopanic_m(gp *g, pc, sp uintptr) bool {
print("\n")
goroutineheader(gp)
traceback(pc, sp, 0, gp)
- } else if level >= 2 || _g_.m.throwing >= throwTypeRuntime {
+ } else if level >= 2 || gp.m.throwing >= throwTypeRuntime {
print("\nruntime stack:\n")
traceback(pc, sp, 0, gp)
}
@@ -1290,29 +1291,32 @@ func dopanic_m(gp *g, pc, sp uintptr) bool {
// panicking.
//
//go:nosplit
-func canpanic(gp *g) bool {
- // Note that g is m->gsignal, different from gp.
- // Note also that g->m can change at preemption, so m can go stale
- // if this function ever makes a function call.
- _g_ := getg()
- mp := _g_.m
+func canpanic() bool {
+ gp := getg()
+ mp := acquirem()
// Is it okay for gp to panic instead of crashing the program?
// Yes, as long as it is running Go code, not runtime code,
// and not stuck in a system call.
- if gp == nil || gp != mp.curg {
+ if gp != mp.curg {
+ releasem(mp)
return false
}
- if mp.locks != 0 || mp.mallocing != 0 || mp.throwing != throwTypeNone || mp.preemptoff != "" || mp.dying != 0 {
+ // N.B. mp.locks != 1 instead of 0 to account for acquirem.
+ if mp.locks != 1 || mp.mallocing != 0 || mp.throwing != throwTypeNone || mp.preemptoff != "" || mp.dying != 0 {
+ releasem(mp)
return false
}
status := readgstatus(gp)
if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
+ releasem(mp)
return false
}
if GOOS == "windows" && mp.libcallsp != 0 {
+ releasem(mp)
return false
}
+ releasem(mp)
return true
}