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_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(); switch(m->dying) { case 0: 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(); return; case 1: // Something failed while panicing, probably the print of the // argument to panic(). Just print a stack trace and exit. m->dying = 2; runtime_printf("panic during panic\n"); runtime_dopanic(0); runtime_exit(3); case 2: // This is a genuine bug in the runtime, we couldn't even // print the stack trace successfully. m->dying = 3; runtime_printf("stack trace unavailable\n"); runtime_exit(4); default: // Can't even print! Just exit. runtime_exit(5); } }
void __go_panic (struct __go_empty_interface arg) { G *g; Panic *n; g = runtime_g (); n = (Panic *) __go_alloc (sizeof (Panic)); n->arg = arg; n->next = g->_panic; g->_panic = n; /* Run all the defer functions. */ while (1) { Defer *d; void (*pfn) (void *); d = g->_defer; if (d == NULL) break; pfn = (void (*) (void *)) d->pfn; d->pfn = 0; if (pfn != NULL) { (*pfn) (d->arg); if (n->recovered) { /* Some defer function called recover. That means that we should stop running this panic. */ g->_panic = n->next; __go_free (n); /* Now unwind the stack by throwing an exception. The compiler has arranged to create exception handlers in each function which uses a defer statement. These exception handlers will check whether the entry on the top of the defer stack is from the current function. If it is, we have unwound the stack far enough. */ __go_unwind_stack (); /* __go_unwind_stack should not return. */ abort (); } /* Because we executed that defer function by a panic, and it did not call recover, we know that we are not returning from the calling function--we are panicing through it. */ *d->frame = 0; } g->_defer = d->next; /* This may be called by a cgo callback routine to defer the call to syscall.CgocallBackDone, in which case we will not have a memory context. Don't try to free anything in that case--the GC will release it later. */ if (runtime_m () != NULL) runtime_freedefer (d); } /* The panic was not recovered. */ runtime_startpanic (); __printpanics (g->_panic); runtime_dopanic (0); }