// Copyright 2009 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 #include #include "config.h" #include "runtime.h" #include "array.h" #include "go-panic.h" // 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); } static int32 argc; static byte** argv; extern Slice os_Args __asm__ (GOSYM_PREFIX "os.Args"); extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs"); void (*runtime_sysargs)(int32, uint8**); void runtime_args(int32 c, byte **v) { argc = c; argv = v; if(runtime_sysargs != nil) runtime_sysargs(c, v); } byte* runtime_progname() { return argc == 0 ? nil : argv[0]; } // Information about what cpu features are available. // Set on startup in asm_{x86/amd64}.s. uint32 runtime_cpuid_ecx; uint32 runtime_cpuid_edx; void runtime_goargs(void) { String *s; int32 i; // for windows implementation see "os" package if(Windows) return; s = runtime_malloc(argc*sizeof s[0]); for(i=0; ifastrand; x += x; if(x & 0x80000000L) x ^= 0x88888eefUL; m->fastrand = x; return x; } int64 runtime_cputicks(void) { #if defined(__386__) || defined(__x86_64__) uint32 low, high; asm("rdtsc" : "=a" (low), "=d" (high)); return (int64)(((uint64)high << 32) | (uint64)low); #else // FIXME: implement for other processors. return 0; #endif } bool runtime_showframe(String s, bool current) { static int32 traceback = -1; if(current && runtime_m()->throwing > 0) return 1; if(traceback < 0) traceback = runtime_gotraceback(nil); return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0); } static Lock ticksLock; static int64 ticks; int64 runtime_tickspersecond(void) { int64 res, t0, t1, c0, c1; res = (int64)runtime_atomicload64((uint64*)&ticks); if(res != 0) return ticks; runtime_lock(&ticksLock); res = ticks; if(res == 0) { t0 = runtime_nanotime(); c0 = runtime_cputicks(); runtime_usleep(100*1000); t1 = runtime_nanotime(); c1 = runtime_cputicks(); if(t1 == t0) t1++; res = (c1-c0)*1000*1000*1000/(t1-t0); if(res == 0) res++; runtime_atomicstore64((uint64*)&ticks, res); } runtime_unlock(&ticksLock); return res; } int64 runtime_pprof_runtime_cyclesPerSecond(void) __asm__ (GOSYM_PREFIX "runtime_pprof.runtime_cyclesPerSecond"); int64 runtime_pprof_runtime_cyclesPerSecond(void) { return runtime_tickspersecond(); } // Called to initialize a new m (including the bootstrap m). // Called on the parent thread (main thread in case of bootstrap), can allocate memory. void runtime_mpreinit(M *mp) { mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K } // Called to initialize a new m (including the bootstrap m). // Called on the new thread, can not allocate memory. void runtime_minit(void) { M* m; sigset_t sigs; // Initialize signal handling. m = runtime_m(); runtime_signalstack(m->gsignalstack, m->gsignalstacksize); if (sigemptyset(&sigs) != 0) runtime_throw("sigemptyset"); sigprocmask(SIG_SETMASK, &sigs, nil); } // Called from dropm to undo the effect of an minit. void runtime_unminit(void) { runtime_signalstack(nil, 0); } void runtime_signalstack(byte *p, int32 n) { stack_t st; st.ss_sp = p; st.ss_size = n; st.ss_flags = 0; if(p == nil) st.ss_flags = SS_DISABLE; if(sigaltstack(&st, nil) < 0) *(int *)0xf1 = 0xf1; }