github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/runtime/panic1.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  // Code related to defer, panic and recover.
     8  // TODO: Merge into panic.go.
     9  
    10  //uint32 runtime·panicking;
    11  var paniclk mutex
    12  
    13  const hasLinkRegister = GOARCH == "arm" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le"
    14  
    15  // Unwind the stack after a deferred function calls recover
    16  // after a panic.  Then arrange to continue running as though
    17  // the caller of the deferred function returned normally.
    18  func recovery(gp *g) {
    19  	// Info about defer passed in G struct.
    20  	sp := gp.sigcode0
    21  	pc := gp.sigcode1
    22  
    23  	// d's arguments need to be in the stack.
    24  	if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) {
    25  		print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
    26  		throw("bad recovery")
    27  	}
    28  
    29  	// Make the deferproc for this d return again,
    30  	// this time returning 1.  The calling function will
    31  	// jump to the standard return epilogue.
    32  	gcUnwindBarriers(gp, sp)
    33  	gp.sched.sp = sp
    34  	gp.sched.pc = pc
    35  	gp.sched.lr = 0
    36  	gp.sched.ret = 1
    37  	gogo(&gp.sched)
    38  }
    39  
    40  func startpanic_m() {
    41  	_g_ := getg()
    42  	if mheap_.cachealloc.size == 0 { // very early
    43  		print("runtime: panic before malloc heap initialized\n")
    44  		_g_.m.mallocing = 1 // tell rest of panic not to try to malloc
    45  	} else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
    46  		_g_.m.mcache = allocmcache()
    47  	}
    48  
    49  	switch _g_.m.dying {
    50  	case 0:
    51  		_g_.m.dying = 1
    52  		if _g_ != nil {
    53  			_g_.writebuf = nil
    54  		}
    55  		xadd(&panicking, 1)
    56  		lock(&paniclk)
    57  		if debug.schedtrace > 0 || debug.scheddetail > 0 {
    58  			schedtrace(true)
    59  		}
    60  		freezetheworld()
    61  		return
    62  	case 1:
    63  		// Something failed while panicing, probably the print of the
    64  		// argument to panic().  Just print a stack trace and exit.
    65  		_g_.m.dying = 2
    66  		print("panic during panic\n")
    67  		dopanic(0)
    68  		exit(3)
    69  		fallthrough
    70  	case 2:
    71  		// This is a genuine bug in the runtime, we couldn't even
    72  		// print the stack trace successfully.
    73  		_g_.m.dying = 3
    74  		print("stack trace unavailable\n")
    75  		exit(4)
    76  		fallthrough
    77  	default:
    78  		// Can't even print!  Just exit.
    79  		exit(5)
    80  	}
    81  }
    82  
    83  var didothers bool
    84  var deadlock mutex
    85  
    86  func dopanic_m(gp *g, pc, sp uintptr) {
    87  	if gp.sig != 0 {
    88  		print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
    89  	}
    90  
    91  	var docrash bool
    92  	_g_ := getg()
    93  	if t := gotraceback(&docrash); t > 0 {
    94  		if gp != gp.m.g0 {
    95  			print("\n")
    96  			goroutineheader(gp)
    97  			traceback(pc, sp, 0, gp)
    98  		} else if t >= 2 || _g_.m.throwing > 0 {
    99  			print("\nruntime stack:\n")
   100  			traceback(pc, sp, 0, gp)
   101  		}
   102  		if !didothers {
   103  			didothers = true
   104  			tracebackothers(gp)
   105  		}
   106  	}
   107  	unlock(&paniclk)
   108  
   109  	if xadd(&panicking, -1) != 0 {
   110  		// Some other m is panicking too.
   111  		// Let it print what it needs to print.
   112  		// Wait forever without chewing up cpu.
   113  		// It will exit when it's done.
   114  		lock(&deadlock)
   115  		lock(&deadlock)
   116  	}
   117  
   118  	if docrash {
   119  		crash()
   120  	}
   121  
   122  	exit(2)
   123  }
   124  
   125  //go:nosplit
   126  func canpanic(gp *g) bool {
   127  	// Note that g is m->gsignal, different from gp.
   128  	// Note also that g->m can change at preemption, so m can go stale
   129  	// if this function ever makes a function call.
   130  	_g_ := getg()
   131  	_m_ := _g_.m
   132  
   133  	// Is it okay for gp to panic instead of crashing the program?
   134  	// Yes, as long as it is running Go code, not runtime code,
   135  	// and not stuck in a system call.
   136  	if gp == nil || gp != _m_.curg {
   137  		return false
   138  	}
   139  	if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
   140  		return false
   141  	}
   142  	status := readgstatus(gp)
   143  	if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
   144  		return false
   145  	}
   146  	if GOOS == "windows" && _m_.libcallsp != 0 {
   147  		return false
   148  	}
   149  	return true
   150  }