From: Nodir Turakulov Date: Fri, 16 Oct 2015 02:00:12 +0000 (-0700) Subject: runtime: merge panic1.go into panic.go X-Git-Tag: go1.6beta1~826 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=9358f7fa6117445af2775076600d8df76616a7fc;p=gostls13.git 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 Run-TryBot: Brad Fitzpatrick --- diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 9a3f4bd486..320c174829 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -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 +} diff --git a/src/runtime/panic1.go b/src/runtime/panic1.go deleted file mode 100644 index 1a71d095b2..0000000000 --- a/src/runtime/panic1.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// Code related to defer, panic and recover. -// TODO: Merge into panic.go. - -//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 -}