f038dae646
From-SVN: r204466
145 lines
3.0 KiB
C
145 lines
3.0 KiB
C
// 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.
|
|
|
|
#include "runtime.h"
|
|
#include "malloc.h"
|
|
#include "go-defer.h"
|
|
#include "go-panic.h"
|
|
|
|
// Code related to defer, panic and recover.
|
|
|
|
uint32 runtime_panicking;
|
|
static Lock paniclk;
|
|
|
|
// Run all deferred functions for the current goroutine.
|
|
static void
|
|
rundefer(void)
|
|
{
|
|
G *g;
|
|
Defer *d;
|
|
|
|
g = runtime_g();
|
|
while((d = g->defer) != nil) {
|
|
void (*pfn)(void*);
|
|
|
|
g->defer = d->__next;
|
|
pfn = d->__pfn;
|
|
d->__pfn = nil;
|
|
if (pfn != nil)
|
|
(*pfn)(d->__arg);
|
|
runtime_free(d);
|
|
}
|
|
}
|
|
|
|
void
|
|
runtime_startpanic(void)
|
|
{
|
|
M *m;
|
|
|
|
m = runtime_m();
|
|
if(runtime_mheap.cachealloc.size == 0) { // very early
|
|
runtime_printf("runtime: panic before malloc heap initialized\n");
|
|
m->mallocing = 1; // tell rest of panic not to try to malloc
|
|
} else if(m->mcache == nil) // can happen if called from signal handler or throw
|
|
m->mcache = runtime_allocmcache();
|
|
if(m->dying) {
|
|
runtime_printf("panic during panic\n");
|
|
runtime_exit(3);
|
|
}
|
|
m->dying = 1;
|
|
if(runtime_g() != nil)
|
|
runtime_g()->writebuf = nil;
|
|
runtime_xadd(&runtime_panicking, 1);
|
|
runtime_lock(&paniclk);
|
|
if(runtime_debug.schedtrace > 0 || runtime_debug.scheddetail > 0)
|
|
runtime_schedtrace(true);
|
|
runtime_freezetheworld();
|
|
}
|
|
|
|
void
|
|
runtime_dopanic(int32 unused __attribute__ ((unused)))
|
|
{
|
|
G *g;
|
|
static bool didothers;
|
|
bool crash;
|
|
int32 t;
|
|
|
|
g = runtime_g();
|
|
if(g->sig != 0)
|
|
runtime_printf("[signal %x code=%p addr=%p]\n",
|
|
g->sig, (void*)g->sigcode0, (void*)g->sigcode1);
|
|
|
|
if((t = runtime_gotraceback(&crash)) > 0){
|
|
if(g != runtime_m()->g0) {
|
|
runtime_printf("\n");
|
|
runtime_goroutineheader(g);
|
|
runtime_traceback();
|
|
runtime_printcreatedby(g);
|
|
} else if(t >= 2 || runtime_m()->throwing > 0) {
|
|
runtime_printf("\nruntime stack:\n");
|
|
runtime_traceback();
|
|
}
|
|
if(!didothers) {
|
|
didothers = true;
|
|
runtime_tracebackothers(g);
|
|
}
|
|
}
|
|
runtime_unlock(&paniclk);
|
|
if(runtime_xadd(&runtime_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.
|
|
static Lock deadlock;
|
|
runtime_lock(&deadlock);
|
|
runtime_lock(&deadlock);
|
|
}
|
|
|
|
if(crash)
|
|
runtime_crash();
|
|
|
|
runtime_exit(2);
|
|
}
|
|
|
|
void
|
|
runtime_throw(const char *s)
|
|
{
|
|
M *mp;
|
|
|
|
mp = runtime_m();
|
|
if(mp->throwing == 0)
|
|
mp->throwing = 1;
|
|
runtime_startpanic();
|
|
runtime_printf("fatal error: %s\n", s);
|
|
runtime_dopanic(0);
|
|
*(int32*)0 = 0; // not reached
|
|
runtime_exit(1); // even more not reached
|
|
}
|
|
|
|
void
|
|
runtime_panicstring(const char *s)
|
|
{
|
|
Eface err;
|
|
|
|
if(runtime_m()->mallocing) {
|
|
runtime_printf("panic: %s\n", s);
|
|
runtime_throw("panic during malloc");
|
|
}
|
|
if(runtime_m()->gcing) {
|
|
runtime_printf("panic: %s\n", s);
|
|
runtime_throw("panic during gc");
|
|
}
|
|
runtime_newErrorCString(s, &err);
|
|
runtime_panic(err);
|
|
}
|
|
|
|
void runtime_Goexit (void) __asm__ (GOSYM_PREFIX "runtime.Goexit");
|
|
|
|
void
|
|
runtime_Goexit(void)
|
|
{
|
|
rundefer();
|
|
runtime_goexit();
|
|
}
|