// 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); if (d->__free) 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(); }