2011-11-14 23:26:45 +01:00
|
|
|
// 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.
|
|
|
|
|
2013-07-24 15:18:45 +02:00
|
|
|
#include <signal.h>
|
2011-11-14 23:26:45 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2012-10-23 06:31:11 +02:00
|
|
|
#include "config.h"
|
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
#include "runtime.h"
|
|
|
|
#include "array.h"
|
|
|
|
#include "go-panic.h"
|
|
|
|
|
2013-07-16 08:54:42 +02:00
|
|
|
// 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)
|
2012-05-17 07:30:25 +02:00
|
|
|
int32
|
2013-07-16 08:54:42 +02:00
|
|
|
runtime_gotraceback(bool *crash)
|
2012-05-17 07:30:25 +02:00
|
|
|
{
|
|
|
|
const byte *p;
|
|
|
|
|
2013-07-16 08:54:42 +02:00
|
|
|
if(crash != nil)
|
|
|
|
*crash = false;
|
2012-05-17 07:30:25 +02:00
|
|
|
p = runtime_getenv("GOTRACEBACK");
|
|
|
|
if(p == nil || p[0] == '\0')
|
|
|
|
return 1; // default is on
|
2013-07-16 08:54:42 +02:00
|
|
|
if(runtime_strcmp((const char *)p, "crash") == 0) {
|
|
|
|
if(crash != nil)
|
|
|
|
*crash = true;
|
|
|
|
return 2; // extra information
|
|
|
|
}
|
2012-05-17 07:30:25 +02:00
|
|
|
return runtime_atoi(p);
|
|
|
|
}
|
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
static int32 argc;
|
|
|
|
static byte** argv;
|
|
|
|
|
2013-01-24 20:44:23 +01:00
|
|
|
extern Slice os_Args __asm__ (GOSYM_PREFIX "os.Args");
|
|
|
|
extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs");
|
2011-11-14 23:26:45 +01:00
|
|
|
|
2012-10-03 07:27:36 +02:00
|
|
|
void (*runtime_sysargs)(int32, uint8**);
|
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
void
|
|
|
|
runtime_args(int32 c, byte **v)
|
|
|
|
{
|
|
|
|
argc = c;
|
|
|
|
argv = v;
|
2012-10-03 07:27:36 +02:00
|
|
|
if(runtime_sysargs != nil)
|
|
|
|
runtime_sysargs(c, v);
|
2011-11-14 23:26:45 +01:00
|
|
|
}
|
|
|
|
|
2012-10-05 15:44:40 +02:00
|
|
|
byte*
|
|
|
|
runtime_progname()
|
|
|
|
{
|
|
|
|
return argc == 0 ? nil : argv[0];
|
|
|
|
}
|
|
|
|
|
2013-07-16 08:54:42 +02:00
|
|
|
// Information about what cpu features are available.
|
|
|
|
// Set on startup in asm_{x86/amd64}.s.
|
|
|
|
uint32 runtime_cpuid_ecx;
|
|
|
|
uint32 runtime_cpuid_edx;
|
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
void
|
|
|
|
runtime_goargs(void)
|
|
|
|
{
|
|
|
|
String *s;
|
|
|
|
int32 i;
|
2012-03-31 00:09:55 +02:00
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
// for windows implementation see "os" package
|
|
|
|
if(Windows)
|
|
|
|
return;
|
|
|
|
|
|
|
|
s = runtime_malloc(argc*sizeof s[0]);
|
|
|
|
for(i=0; i<argc; i++)
|
2011-11-30 01:21:52 +01:00
|
|
|
s[i] = runtime_gostringnocopy((const byte*)argv[i]);
|
2011-11-14 23:26:45 +01:00
|
|
|
os_Args.__values = (void*)s;
|
|
|
|
os_Args.__count = argc;
|
|
|
|
os_Args.__capacity = argc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-01-25 21:56:26 +01:00
|
|
|
runtime_goenvs_unix(void)
|
2011-11-14 23:26:45 +01:00
|
|
|
{
|
|
|
|
String *s;
|
|
|
|
int32 i, n;
|
2012-03-31 00:09:55 +02:00
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
for(n=0; argv[argc+1+n] != 0; n++)
|
|
|
|
;
|
|
|
|
|
|
|
|
s = runtime_malloc(n*sizeof s[0]);
|
|
|
|
for(i=0; i<n; i++)
|
|
|
|
s[i] = runtime_gostringnocopy(argv[argc+1+i]);
|
2011-12-13 00:40:51 +01:00
|
|
|
syscall_Envs.__values = (void*)s;
|
|
|
|
syscall_Envs.__count = n;
|
|
|
|
syscall_Envs.__capacity = n;
|
2011-11-14 23:26:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int32
|
|
|
|
runtime_atoi(const byte *p)
|
|
|
|
{
|
|
|
|
int32 n;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while('0' <= *p && *p <= '9')
|
|
|
|
n = n*10 + *p++ - '0';
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2013-07-16 08:54:42 +02:00
|
|
|
static struct root_list runtime_roots =
|
|
|
|
{ nil,
|
|
|
|
{ { &syscall_Envs, sizeof syscall_Envs },
|
|
|
|
{ &os_Args, sizeof os_Args },
|
|
|
|
{ nil, 0 } },
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
TestAtomic64(void)
|
|
|
|
{
|
|
|
|
uint64 z64, x64;
|
|
|
|
|
|
|
|
z64 = 42;
|
|
|
|
x64 = 0;
|
|
|
|
PREFETCH(&z64);
|
|
|
|
if(runtime_cas64(&z64, &x64, 1))
|
|
|
|
runtime_throw("cas64 failed");
|
|
|
|
if(x64 != 42)
|
|
|
|
runtime_throw("cas64 failed");
|
|
|
|
if(!runtime_cas64(&z64, &x64, 1))
|
|
|
|
runtime_throw("cas64 failed");
|
|
|
|
if(x64 != 42 || z64 != 1)
|
|
|
|
runtime_throw("cas64 failed");
|
|
|
|
if(runtime_atomicload64(&z64) != 1)
|
|
|
|
runtime_throw("load64 failed");
|
|
|
|
runtime_atomicstore64(&z64, (1ull<<40)+1);
|
|
|
|
if(runtime_atomicload64(&z64) != (1ull<<40)+1)
|
|
|
|
runtime_throw("store64 failed");
|
|
|
|
if(runtime_xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
|
|
|
|
runtime_throw("xadd64 failed");
|
|
|
|
if(runtime_atomicload64(&z64) != (2ull<<40)+2)
|
|
|
|
runtime_throw("xadd64 failed");
|
|
|
|
if(runtime_xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
|
|
|
|
runtime_throw("xchg64 failed");
|
|
|
|
if(runtime_atomicload64(&z64) != (3ull<<40)+3)
|
|
|
|
runtime_throw("xchg64 failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
runtime_check(void)
|
|
|
|
{
|
|
|
|
__go_register_gc_roots(&runtime_roots);
|
|
|
|
|
|
|
|
TestAtomic64();
|
|
|
|
}
|
|
|
|
|
2011-11-14 23:26:45 +01:00
|
|
|
uint32
|
|
|
|
runtime_fastrand1(void)
|
|
|
|
{
|
2011-11-28 06:45:49 +01:00
|
|
|
M *m;
|
2011-11-14 23:26:45 +01:00
|
|
|
uint32 x;
|
|
|
|
|
2011-11-28 06:45:49 +01:00
|
|
|
m = runtime_m();
|
2011-11-14 23:26:45 +01:00
|
|
|
x = m->fastrand;
|
|
|
|
x += x;
|
|
|
|
if(x & 0x80000000L)
|
|
|
|
x ^= 0x88888eefUL;
|
|
|
|
m->fastrand = x;
|
|
|
|
return x;
|
|
|
|
}
|
2012-01-25 21:56:26 +01:00
|
|
|
|
2012-02-09 09:19:58 +01:00
|
|
|
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
|
|
|
|
}
|
2012-05-17 07:30:25 +02:00
|
|
|
|
|
|
|
bool
|
2013-01-30 02:37:13 +01:00
|
|
|
runtime_showframe(String s, bool current)
|
2012-05-17 07:30:25 +02:00
|
|
|
{
|
|
|
|
static int32 traceback = -1;
|
2013-01-30 02:37:13 +01:00
|
|
|
|
|
|
|
if(current && runtime_m()->throwing > 0)
|
|
|
|
return 1;
|
2012-05-17 07:30:25 +02:00
|
|
|
if(traceback < 0)
|
2013-07-16 08:54:42 +02:00
|
|
|
traceback = runtime_gotraceback(nil);
|
2012-11-21 08:03:38 +01:00
|
|
|
return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
|
2012-05-17 07:30:25 +02:00
|
|
|
}
|
2012-05-24 22:44:34 +02:00
|
|
|
|
2012-10-23 06:31:11 +02:00
|
|
|
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)
|
2013-01-24 20:44:23 +01:00
|
|
|
__asm__ (GOSYM_PREFIX "runtime_pprof.runtime_cyclesPerSecond");
|
2012-10-23 06:31:11 +02:00
|
|
|
|
|
|
|
int64
|
|
|
|
runtime_pprof_runtime_cyclesPerSecond(void)
|
2012-05-24 22:44:34 +02:00
|
|
|
{
|
2012-10-23 06:31:11 +02:00
|
|
|
return runtime_tickspersecond();
|
2012-05-24 22:44:34 +02:00
|
|
|
}
|
2013-07-24 15:18:45 +02:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|