// The GOTRACEBACK environment variable controls the // behavior of a Go program that is crashing and exiting. // GOTRACEBACK=0 suppress all tracebacks // GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames // GOTRACEBACK=2 show tracebacks including runtime frames // GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc) int32 runtime_gotraceback(bool *crash) { const byte *p; uint32 x; if(crash != nil) *crash = false; if(runtime_m()->traceback != 0) return runtime_m()->traceback; x = runtime_atomicload(&traceback_cache); if(x == ~(uint32)0) { p = runtime_getenv("GOTRACEBACK"); if(p == nil) p = (const byte*)""; if(p[0] == '\0') x = 1<<1; else if(runtime_strcmp((const char *)p, "crash") == 0) x = (2<<1) | 1; else x = runtime_atoi(p)<<1; runtime_atomicstore(&traceback_cache, x); } if(crash != nil) *crash = x&1; return x>>1; }
// The bootstrap sequence is: // // call osinit // call schedinit // make & queue new G // call runtime_mstart // // The new G calls runtime_main. void runtime_schedinit(void) { int32 n; const byte *p; m = &runtime_m0; g = &runtime_g0; m->g0 = g; m->curg = g; g->m = m; initcontext(); inittlssize(); m->nomemprof++; runtime_mallocinit(); mcommoninit(m); runtime_goargs(); runtime_goenvs(); // For debugging: // Allocate internal symbol table representation now, // so that we don't need to call malloc when we crash. // runtime_findfunc(0); runtime_gomaxprocs = 1; p = runtime_getenv("GOMAXPROCS"); if(p != nil && (n = runtime_atoi(p)) != 0) { if(n > maxgomaxprocs) n = maxgomaxprocs; runtime_gomaxprocs = n; } // wait for the main goroutine to start before taking // GOMAXPROCS into account. setmcpumax(1); runtime_singleproc = runtime_gomaxprocs == 1; canaddmcpu(); // mcpu++ to account for bootstrap m m->helpgc = 1; // flag to tell schedule() to mcpu-- runtime_sched.grunning++; // Can not enable GC until all roots are registered. // mstats.enablegc = 1; m->nomemprof--; }
// The GOTRACEBACK environment variable controls the // behavior of a Go program that is crashing and exiting. // GOTRACEBACK=0 suppress all tracebacks // GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames // GOTRACEBACK=2 show tracebacks including runtime frames // GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc) int32 runtime_gotraceback(bool *crash) { const byte *p; if(crash != nil) *crash = false; p = runtime_getenv("GOTRACEBACK"); if(p == nil || p[0] == '\0') return 1; // default is on if(runtime_strcmp((const char *)p, "crash") == 0) { if(crash != nil) *crash = true; return 2; // extra information } return runtime_atoi(p); }
void runtime_parsedebugvars(void) { const byte *p; intgo i, n; p = runtime_getenv("GODEBUG"); if(p == nil) return; for(;;) { for(i=0; i<(intgo)nelem(dbgvar); i++) { n = runtime_findnull((const byte*)dbgvar[i].name); if(runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=') *dbgvar[i].value = runtime_atoi(p+n+1); } p = (const byte *)runtime_strstr((const char *)p, ","); if(p == nil) break; p++; } }
void runtime_gc(int32 force __attribute__ ((unused))) { int64 t0, t1; char *p; Finalizer *fp; // The gc is turned off (via enablegc) until // the bootstrap has completed. // Also, malloc gets called in the guts // of a number of libraries that might be // holding locks. To avoid priority inversion // problems, don't bother trying to run gc // while holding a lock. The next mallocgc // without a lock will do the gc instead. if(!mstats.enablegc || m->locks > 0 /* || runtime_panicking */) return; if(gcpercent == -2) { // first time through p = runtime_getenv("GOGC"); if(p == nil || p[0] == '\0') gcpercent = 100; else if(runtime_strcmp(p, "off") == 0) gcpercent = -1; else gcpercent = runtime_atoi(p); } if(gcpercent < 0) return; pthread_mutex_lock(&finqlock); pthread_mutex_lock(&gcsema); m->locks++; // disable gc during the mallocs in newproc t0 = runtime_nanotime(); runtime_stoptheworld(); if(force || mstats.heap_alloc >= mstats.next_gc) { __go_cachestats(); mark(); sweep(); __go_stealcache(); mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100; } t1 = runtime_nanotime(); mstats.numgc++; mstats.pause_ns += t1 - t0; if(mstats.debuggc) runtime_printf("pause %llu\n", (unsigned long long)t1-t0); pthread_mutex_unlock(&gcsema); runtime_starttheworld(); // finqlock is still held. fp = finq; if(fp != nil) { // kick off or wake up goroutine to run queued finalizers if(!finstarted) { __go_go(runfinq, nil); finstarted = 1; } else if(fingwait) { fingwait = 0; pthread_cond_signal(&finqcond); } } m->locks--; pthread_mutex_unlock(&finqlock); }