1
0
mirror of https://github.com/golang/go synced 2024-10-04 19:21:21 -06:00
go/src/runtime/panic1.go
Russ Cox 3e804631d9 [dev.cc] all: merge dev.power64 (7667e41f3ced) into dev.cc
This is to reduce the delta between dev.cc and dev.garbage to just garbage collector changes.

These are the files that had merge conflicts and have been edited by hand:
        malloc.go
        mem_linux.go
        mgc.go
        os1_linux.go
        proc1.go
        panic1.go
        runtime1.go

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/174180043
2014-11-14 12:10:52 -05:00

162 lines
4.1 KiB
Go

// 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
import "unsafe"
// Code related to defer, panic and recover.
// TODO: Merge into panic.go.
//uint32 runtime·panicking;
var paniclk mutex
const hasLinkRegister = GOARCH == "arm" || GOARCH == "power64" || GOARCH == "power64le"
// 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.
argp := (unsafe.Pointer)(gp.sigcode0)
pc := uintptr(gp.sigcode1)
// d's arguments need to be in the stack.
if argp != nil && (uintptr(argp) < gp.stack.lo || gp.stack.hi < uintptr(argp)) {
print("recover: ", argp, " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
gothrow("bad recovery")
}
// Make the deferproc for this d return again,
// this time returning 1. The calling function will
// jump to the standard return epilogue.
// The -2*sizeof(uintptr) makes up for the
// two extra words that are on the stack at
// each call to deferproc.
// (The pc we're returning to does pop pop
// before it tests the return value.)
// On the arm and power there are 2 saved LRs mixed in too.
if hasLinkRegister {
gp.sched.sp = uintptr(argp) - 4*ptrSize
} else {
gp.sched.sp = uintptr(argp) - 2*ptrSize
}
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_.gcing != 0 || _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
}