mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: merge panic1.go into panic.go
A TODO to merge is removed from panic1.go. The rest is appended to panic.go Updates #12952 Change-Id: Ied4382a455abc20bc2938e34d031802e6b4baf8b Reviewed-on: https://go-review.googlesource.com/15905 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
d72d299f3e
commit
9358f7fa61
2 changed files with 142 additions and 150 deletions
|
|
@ -527,3 +527,145 @@ func throw(s string) {
|
|||
dopanic(0)
|
||||
*(*int)(nil) = 0 // not reached
|
||||
}
|
||||
|
||||
//uint32 runtime·panicking;
|
||||
var paniclk mutex
|
||||
|
||||
const hasLinkRegister = GOARCH == "arm" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le"
|
||||
|
||||
// Unwind the stack after a deferred function calls recover
|
||||
// after a panic. Then arrange to continue running as though
|
||||
// the caller of the deferred function returned normally.
|
||||
func recovery(gp *g) {
|
||||
// Info about defer passed in G struct.
|
||||
sp := gp.sigcode0
|
||||
pc := gp.sigcode1
|
||||
|
||||
// d's arguments need to be in the stack.
|
||||
if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) {
|
||||
print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
|
||||
throw("bad recovery")
|
||||
}
|
||||
|
||||
// Make the deferproc for this d return again,
|
||||
// this time returning 1. The calling function will
|
||||
// jump to the standard return epilogue.
|
||||
gcUnwindBarriers(gp, sp)
|
||||
gp.sched.sp = sp
|
||||
gp.sched.pc = pc
|
||||
gp.sched.lr = 0
|
||||
gp.sched.ret = 1
|
||||
gogo(&gp.sched)
|
||||
}
|
||||
|
||||
func startpanic_m() {
|
||||
_g_ := getg()
|
||||
if mheap_.cachealloc.size == 0 { // very early
|
||||
print("runtime: panic before malloc heap initialized\n")
|
||||
_g_.m.mallocing = 1 // tell rest of panic not to try to malloc
|
||||
} else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
|
||||
_g_.m.mcache = allocmcache()
|
||||
}
|
||||
|
||||
switch _g_.m.dying {
|
||||
case 0:
|
||||
_g_.m.dying = 1
|
||||
if _g_ != nil {
|
||||
_g_.writebuf = nil
|
||||
}
|
||||
xadd(&panicking, 1)
|
||||
lock(&paniclk)
|
||||
if debug.schedtrace > 0 || debug.scheddetail > 0 {
|
||||
schedtrace(true)
|
||||
}
|
||||
freezetheworld()
|
||||
return
|
||||
case 1:
|
||||
// Something failed while panicing, probably the print of the
|
||||
// argument to panic(). Just print a stack trace and exit.
|
||||
_g_.m.dying = 2
|
||||
print("panic during panic\n")
|
||||
dopanic(0)
|
||||
exit(3)
|
||||
fallthrough
|
||||
case 2:
|
||||
// This is a genuine bug in the runtime, we couldn't even
|
||||
// print the stack trace successfully.
|
||||
_g_.m.dying = 3
|
||||
print("stack trace unavailable\n")
|
||||
exit(4)
|
||||
fallthrough
|
||||
default:
|
||||
// Can't even print! Just exit.
|
||||
exit(5)
|
||||
}
|
||||
}
|
||||
|
||||
var didothers bool
|
||||
var deadlock mutex
|
||||
|
||||
func dopanic_m(gp *g, pc, sp uintptr) {
|
||||
if gp.sig != 0 {
|
||||
print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
|
||||
}
|
||||
|
||||
var docrash bool
|
||||
_g_ := getg()
|
||||
if t := gotraceback(&docrash); t > 0 {
|
||||
if gp != gp.m.g0 {
|
||||
print("\n")
|
||||
goroutineheader(gp)
|
||||
traceback(pc, sp, 0, gp)
|
||||
} else if t >= 2 || _g_.m.throwing > 0 {
|
||||
print("\nruntime stack:\n")
|
||||
traceback(pc, sp, 0, gp)
|
||||
}
|
||||
if !didothers {
|
||||
didothers = true
|
||||
tracebackothers(gp)
|
||||
}
|
||||
}
|
||||
unlock(&paniclk)
|
||||
|
||||
if xadd(&panicking, -1) != 0 {
|
||||
// Some other m is panicking too.
|
||||
// Let it print what it needs to print.
|
||||
// Wait forever without chewing up cpu.
|
||||
// It will exit when it's done.
|
||||
lock(&deadlock)
|
||||
lock(&deadlock)
|
||||
}
|
||||
|
||||
if docrash {
|
||||
crash()
|
||||
}
|
||||
|
||||
exit(2)
|
||||
}
|
||||
|
||||
//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()
|
||||
_m_ := _g_.m
|
||||
|
||||
// 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 != _m_.curg {
|
||||
return false
|
||||
}
|
||||
if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
|
||||
return false
|
||||
}
|
||||
status := readgstatus(gp)
|
||||
if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
|
||||
return false
|
||||
}
|
||||
if GOOS == "windows" && _m_.libcallsp != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue