static void sig_handler (int sig) { int i; #ifdef SIGPROF if (sig == SIGPROF) { /* FIXME. */ runtime_sigprof (0, 0, nil, nil); return; } #endif for (i = 0; runtime_sigtab[i].sig != -1; ++i) { struct sigaction sa; SigTab *t; t = &runtime_sigtab[i]; if (t->sig != sig) continue; if ((t->flags & SigNotify) != 0) { if (__go_sigsend (sig)) return; } if ((t->flags & SigKill) != 0) runtime_exit (2); if ((t->flags & SigThrow) == 0) return; runtime_startpanic (); /* We should do a stack backtrace here. Until we can do that, we reraise the signal in order to get a slightly better report from the shell. */ memset (&sa, 0, sizeof sa); sa.sa_handler = SIG_DFL; i = sigemptyset (&sa.sa_mask); __go_assert (i == 0); if (sigaction (sig, &sa, NULL) != 0) abort (); raise (sig); runtime_exit (2); } __builtin_unreachable (); }
// The main goroutine. void runtime_main(void) { // Lock the main goroutine onto this, the main OS thread, // during initialization. Most programs won't care, but a few // do require certain calls to be made by the main thread. // Those can arrange for main.main to run in the main thread // by calling runtime.LockOSThread during initialization // to preserve the lock. runtime_LockOSThread(); // From now on, newgoroutines may use non-main threads. setmcpumax(runtime_gomaxprocs); runtime_sched.init = true; scvg = __go_go(runtime_MHeap_Scavenger, nil); main_init(); runtime_sched.init = false; if(!runtime_sched.lockmain) runtime_UnlockOSThread(); // For gccgo we have to wait until after main is initialized // to enable GC, because initializing main registers the GC // roots. mstats.enablegc = 1; // The deadlock detection has false negatives. // Let scvg start up, to eliminate the false negative // for the trivial program func main() { select{} }. runtime_gosched(); main_main(); runtime_exit(0); for(;;) *(int32*)0 = 0; }
// The main goroutine. void runtime_main(void) { // Lock the main goroutine onto this, the main OS thread, // during initialization. Most programs won't care, but a few // do require certain calls to be made by the main thread. // Those can arrange for main.main to run in the main thread // by calling runtime.LockOSThread during initialization // to preserve the lock. runtime_LockOSThread(); runtime_sched.init = true; main_init(); runtime_sched.init = false; if(!runtime_sched.lockmain) runtime_UnlockOSThread(); // For gccgo we have to wait until after main is initialized // to enable GC, because initializing main registers the GC // roots. mstats.enablegc = 1; main_main(); runtime_exit(0); for(;;) *(int32*)0 = 0; }
static void runtime_badsignal(int32 sig) { if (sig == SIGPROF) { return; // Ignore SIGPROFs intended for a non-Go thread. } runtime_write(2, badsignal, sizeof badsignal - 1); runtime_exit(1); }
void pabort(const char *format, ...) { va_list args; va_start(args, format); printf("ABORT: "); vfprintf(stderr, format, args); va_end(args); runtime_exit(); }
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 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_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); }
// One round of scheduler: find a goroutine and run it. // The argument is the goroutine that was running before // schedule was called, or nil if this is the first call. // Never returns. static void schedule(G *gp) { int32 hz; uint32 v; schedlock(); if(gp != nil) { // Just finished running gp. gp->m = nil; runtime_sched.grunning--; // atomic { mcpu-- } v = runtime_xadd(&runtime_sched.atomic, -1<<mcpuShift); if(atomic_mcpu(v) > maxgomaxprocs) runtime_throw("negative mcpu in scheduler"); switch(gp->status){ case Grunnable: case Gdead: // Shouldn't have been running! runtime_throw("bad gp->status in sched"); case Grunning: gp->status = Grunnable; gput(gp); break; case Gmoribund: gp->status = Gdead; if(gp->lockedm) { gp->lockedm = nil; m->lockedg = nil; } gp->idlem = nil; runtime_memclr(&gp->context, sizeof gp->context); gfput(gp); if(--runtime_sched.gcount == 0) runtime_exit(0); break; } if(gp->readyonstop){ gp->readyonstop = 0; readylocked(gp); } } else if(m->helpgc) { // Bootstrap m or new m started by starttheworld. // atomic { mcpu-- } v = runtime_xadd(&runtime_sched.atomic, -1<<mcpuShift); if(atomic_mcpu(v) > maxgomaxprocs) runtime_throw("negative mcpu in scheduler"); // Compensate for increment in starttheworld(). runtime_sched.grunning--; m->helpgc = 0; } else if(m->nextg != nil) { // New m started by matchmg. } else { runtime_throw("invalid m state in scheduler"); } // Find (or wait for) g to run. Unlocks runtime_sched. gp = nextgandunlock(); gp->readyonstop = 0; gp->status = Grunning; m->curg = gp; gp->m = m; // Check whether the profiler needs to be turned on or off. hz = runtime_sched.profilehz; if(m->profilehz != hz) runtime_resetcpuprofiler(hz); runtime_gogo(gp); }
static void sig_handler (int sig) { int i; if (runtime_m () == NULL) { runtime_badsignal (sig); return; } #ifdef SIGPROF if (sig == SIGPROF) { runtime_sigprof (); return; } #endif for (i = 0; runtime_sigtab[i].sig != -1; ++i) { SigTab *t; t = &runtime_sigtab[i]; if (t->sig != sig) continue; if ((t->flags & SigNotify) != 0) { if (__go_sigsend (sig)) return; } if ((t->flags & SigKill) != 0) runtime_exit (2); if ((t->flags & SigThrow) == 0) return; runtime_startpanic (); { const char *name = NULL; #ifdef HAVE_STRSIGNAL name = strsignal (sig); #endif if (name == NULL) runtime_printf ("Signal %d\n", sig); else runtime_printf ("%s\n", name); } runtime_printf ("\n"); if (runtime_gotraceback ()) { G *g; g = runtime_g (); runtime_traceback (g); runtime_tracebackothers (g); /* The gc library calls runtime_dumpregs here, and provides a function that prints the registers saved in context in a readable form. */ } runtime_exit (2); } __builtin_unreachable (); }
void exit(int status) { printf("Exit called with %d\n", status); runtime_exit(); }