github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/runtime/runtime.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <signal.h>
     6  #include <unistd.h>
     7  
     8  #include "config.h"
     9  
    10  #include "runtime.h"
    11  #include "arch.h"
    12  #include "array.h"
    13  
    14  enum {
    15  	maxround = sizeof(uintptr),
    16  };
    17  
    18  // Keep a cached value to make gotraceback fast,
    19  // since we call it on every call to gentraceback.
    20  // The cached value is a uint32 in which the low bit
    21  // is the "crash" setting and the top 31 bits are the
    22  // gotraceback value.
    23  static uint32 traceback_cache = ~(uint32)0;
    24  
    25  extern volatile intgo runtime_MemProfileRate
    26    __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
    27  
    28  
    29  // The GOTRACEBACK environment variable controls the
    30  // behavior of a Go program that is crashing and exiting.
    31  //	GOTRACEBACK=0   suppress all tracebacks
    32  //	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
    33  //	GOTRACEBACK=2   show tracebacks including runtime frames
    34  //	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
    35  int32
    36  runtime_gotraceback(bool *crash)
    37  {
    38  	const byte *p;
    39  	uint32 x;
    40  
    41  	if(crash != nil)
    42  		*crash = false;
    43  	if(runtime_m()->traceback != 0)
    44  		return runtime_m()->traceback;
    45  	x = runtime_atomicload(&traceback_cache);
    46  	if(x == ~(uint32)0) {
    47  		p = runtime_getenv("GOTRACEBACK");
    48  		if(p == nil)
    49  			p = (const byte*)"";
    50  		if(p[0] == '\0')
    51  			x = 1<<1;
    52  		else if(runtime_strcmp((const char *)p, "crash") == 0)
    53  			x = (2<<1) | 1;
    54  		else
    55  			x = runtime_atoi(p)<<1;	
    56  		runtime_atomicstore(&traceback_cache, x);
    57  	}
    58  	if(crash != nil)
    59  		*crash = x&1;
    60  	return x>>1;
    61  }
    62  
    63  static int32	argc;
    64  static byte**	argv;
    65  
    66  static Slice args;
    67  Slice envs;
    68  
    69  void (*runtime_sysargs)(int32, uint8**);
    70  
    71  void
    72  runtime_args(int32 c, byte **v)
    73  {
    74  	argc = c;
    75  	argv = v;
    76  	if(runtime_sysargs != nil)
    77  		runtime_sysargs(c, v);
    78  }
    79  
    80  byte*
    81  runtime_progname()
    82  {
    83    return argc == 0 ? nil : argv[0];
    84  }
    85  
    86  void
    87  runtime_goargs(void)
    88  {
    89  	String *s;
    90  	int32 i;
    91  
    92  	// for windows implementation see "os" package
    93  	if(Windows)
    94  		return;
    95  
    96  	s = runtime_malloc(argc*sizeof s[0]);
    97  	for(i=0; i<argc; i++)
    98  		s[i] = runtime_gostringnocopy((const byte*)argv[i]);
    99  	args.__values = (void*)s;
   100  	args.__count = argc;
   101  	args.__capacity = argc;
   102  }
   103  
   104  void
   105  runtime_goenvs_unix(void)
   106  {
   107  	String *s;
   108  	int32 i, n;
   109  
   110  	for(n=0; argv[argc+1+n] != 0; n++)
   111  		;
   112  
   113  	s = runtime_malloc(n*sizeof s[0]);
   114  	for(i=0; i<n; i++)
   115  		s[i] = runtime_gostringnocopy(argv[argc+1+i]);
   116  	envs.__values = (void*)s;
   117  	envs.__count = n;
   118  	envs.__capacity = n;
   119  }
   120  
   121  // Called from the syscall package.
   122  Slice runtime_envs(void) __asm__ (GOSYM_PREFIX "syscall.runtime_envs");
   123  
   124  Slice
   125  runtime_envs()
   126  {
   127  	return envs;
   128  }
   129  
   130  Slice os_runtime_args(void) __asm__ (GOSYM_PREFIX "os.runtime_args");
   131  
   132  Slice
   133  os_runtime_args()
   134  {
   135  	return args;
   136  }
   137  
   138  int32
   139  runtime_atoi(const byte *p)
   140  {
   141  	int32 n;
   142  
   143  	n = 0;
   144  	while('0' <= *p && *p <= '9')
   145  		n = n*10 + *p++ - '0';
   146  	return n;
   147  }
   148  
   149  static struct root_list runtime_roots =
   150  { nil,
   151    { { &envs, sizeof envs },
   152      { &args, sizeof args },
   153      { nil, 0 } },
   154  };
   155  
   156  static void
   157  TestAtomic64(void)
   158  {
   159  	uint64 z64, x64;
   160  
   161  	z64 = 42;
   162  	x64 = 0;
   163  	PREFETCH(&z64);
   164  	if(runtime_cas64(&z64, x64, 1))
   165  		runtime_throw("cas64 failed");
   166  	if(x64 != 0)
   167  		runtime_throw("cas64 failed");
   168  	x64 = 42;
   169  	if(!runtime_cas64(&z64, x64, 1))
   170  		runtime_throw("cas64 failed");
   171  	if(x64 != 42 || z64 != 1)
   172  		runtime_throw("cas64 failed");
   173  	if(runtime_atomicload64(&z64) != 1)
   174  		runtime_throw("load64 failed");
   175  	runtime_atomicstore64(&z64, (1ull<<40)+1);
   176  	if(runtime_atomicload64(&z64) != (1ull<<40)+1)
   177  		runtime_throw("store64 failed");
   178  	if(runtime_xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
   179  		runtime_throw("xadd64 failed");
   180  	if(runtime_atomicload64(&z64) != (2ull<<40)+2)
   181  		runtime_throw("xadd64 failed");
   182  	if(runtime_xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
   183  		runtime_throw("xchg64 failed");
   184  	if(runtime_atomicload64(&z64) != (3ull<<40)+3)
   185  		runtime_throw("xchg64 failed");
   186  }
   187  
   188  void
   189  runtime_check(void)
   190  {
   191  	__go_register_gc_roots(&runtime_roots);
   192  
   193  	TestAtomic64();
   194  }
   195  
   196  uint32
   197  runtime_fastrand1(void)
   198  {
   199  	M *m;
   200  	uint32 x;
   201  
   202  	m = runtime_m();
   203  	x = m->fastrand;
   204  	x += x;
   205  	if(x & 0x80000000L)
   206  		x ^= 0x88888eefUL;
   207  	m->fastrand = x;
   208  	return x;
   209  }
   210  
   211  int64
   212  runtime_cputicks(void)
   213  {
   214  #if defined(__386__) || defined(__x86_64__)
   215    uint32 low, high;
   216    asm("rdtsc" : "=a" (low), "=d" (high));
   217    return (int64)(((uint64)high << 32) | (uint64)low);
   218  #elif defined (__s390__) || defined (__s390x__)
   219    uint64 clock = 0;
   220    /* stckf may not write the return variable in case of a clock error, so make
   221       it read-write to prevent that the initialisation is optimised out.
   222       Note: Targets below z9-109 will crash when executing store clock fast, i.e.
   223       we don't support Go for machines older than that.  */
   224    asm volatile(".insn s,0xb27c0000,%0" /* stckf */ : "+Q" (clock) : : "cc" );
   225    return (int64)clock;
   226  #else
   227    // FIXME: implement for other processors.
   228    return 0;
   229  #endif
   230  }
   231  
   232  bool
   233  runtime_showframe(String s, bool current)
   234  {
   235  	static int32 traceback = -1;
   236  
   237  	if(current && runtime_m()->throwing > 0)
   238  		return 1;
   239  	if(traceback < 0)
   240  		traceback = runtime_gotraceback(nil);
   241  	return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
   242  }
   243  
   244  static Lock ticksLock;
   245  static int64 ticks;
   246  
   247  int64
   248  runtime_tickspersecond(void)
   249  {
   250  	int64 res, t0, t1, c0, c1;
   251  
   252  	res = (int64)runtime_atomicload64((uint64*)&ticks);
   253  	if(res != 0)
   254  		return ticks;
   255  	runtime_lock(&ticksLock);
   256  	res = ticks;
   257  	if(res == 0) {
   258  		t0 = runtime_nanotime();
   259  		c0 = runtime_cputicks();
   260  		runtime_usleep(100*1000);
   261  		t1 = runtime_nanotime();
   262  		c1 = runtime_cputicks();
   263  		if(t1 == t0)
   264  			t1++;
   265  		res = (c1-c0)*1000*1000*1000/(t1-t0);
   266  		if(res == 0)
   267  			res++;
   268  		runtime_atomicstore64((uint64*)&ticks, res);
   269  	}
   270  	runtime_unlock(&ticksLock);
   271  	return res;
   272  }
   273  
   274  // Called to initialize a new m (including the bootstrap m).
   275  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   276  void
   277  runtime_mpreinit(M *mp)
   278  {
   279  	mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize);	// OS X wants >=8K, Linux >=2K
   280  }
   281  
   282  // Called to initialize a new m (including the bootstrap m).
   283  // Called on the new thread, can not allocate memory.
   284  void
   285  runtime_minit(void)
   286  {
   287  	M* m;
   288  	sigset_t sigs;
   289  
   290  	// Initialize signal handling.
   291  	m = runtime_m();
   292  	runtime_signalstack(m->gsignalstack, m->gsignalstacksize);
   293  	if (sigemptyset(&sigs) != 0)
   294  		runtime_throw("sigemptyset");
   295  	pthread_sigmask(SIG_SETMASK, &sigs, nil);
   296  }
   297  
   298  // Called from dropm to undo the effect of an minit.
   299  void
   300  runtime_unminit(void)
   301  {
   302  	runtime_signalstack(nil, 0);
   303  }
   304  
   305  
   306  void
   307  runtime_signalstack(byte *p, int32 n)
   308  {
   309  	stack_t st;
   310  
   311  	st.ss_sp = p;
   312  	st.ss_size = n;
   313  	st.ss_flags = 0;
   314  	if(p == nil)
   315  		st.ss_flags = SS_DISABLE;
   316  	if(sigaltstack(&st, nil) < 0)
   317  		*(int *)0xf1 = 0xf1;
   318  }
   319  
   320  DebugVars	runtime_debug;
   321  
   322  // Holds variables parsed from GODEBUG env var,
   323  // except for "memprofilerate" since there is an
   324  // existing var for that value which is int
   325  // instead of in32 and might have an
   326  // initial value.
   327  static struct {
   328  	const char* name;
   329  	int32*	value;
   330  } dbgvar[] = {
   331  	{"allocfreetrace", &runtime_debug.allocfreetrace},
   332  	{"efence", &runtime_debug.efence},
   333  	{"gctrace", &runtime_debug.gctrace},
   334  	{"gcdead", &runtime_debug.gcdead},
   335  	{"scheddetail", &runtime_debug.scheddetail},
   336  	{"schedtrace", &runtime_debug.schedtrace},
   337  };
   338  
   339  void
   340  runtime_parsedebugvars(void)
   341  {
   342  	const byte *p;
   343  	intgo i, n;
   344  	bool tmp;
   345  	
   346  	// gotraceback caches the GOTRACEBACK setting in traceback_cache.
   347  	// gotraceback can be called before the environment is available.
   348  	// traceback_cache must be reset after the environment is made
   349  	// available, in order for the environment variable to take effect.
   350  	// The code is fixed differently in Go 1.4.
   351  	// This is a limited fix for Go 1.3.3.
   352  	traceback_cache = ~(uint32)0;
   353  	runtime_gotraceback(&tmp);
   354  
   355  	p = runtime_getenv("GODEBUG");
   356  	if(p == nil)
   357  		return;
   358  	for(;;) {
   359  		for(i=0; i<(intgo)nelem(dbgvar); i++) {
   360  			n = runtime_findnull((const byte*)dbgvar[i].name);
   361  			if(runtime_mcmp(p, "memprofilerate", n) == 0 && p[n] == '=')
   362  				// Set the MemProfileRate directly since it
   363  				// is an int, not int32, and should only lbe
   364  				// set here if specified by GODEBUG
   365  				runtime_MemProfileRate = runtime_atoi(p+n+1);
   366  			else if(runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=')
   367  				*dbgvar[i].value = runtime_atoi(p+n+1);
   368  		}
   369  		p = (const byte *)runtime_strstr((const char *)p, ",");
   370  		if(p == nil)
   371  			break;
   372  		p++;
   373  	}
   374  }
   375  
   376  // Poor mans 64-bit division.
   377  // This is a very special function, do not use it if you are not sure what you are doing.
   378  // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
   379  // Handles overflow in a time-specific manner.
   380  int32
   381  runtime_timediv(int64 v, int32 div, int32 *rem)
   382  {
   383  	int32 res, bit;
   384  
   385  	if(v >= (int64)div*0x7fffffffLL) {
   386  		if(rem != nil)
   387  			*rem = 0;
   388  		return 0x7fffffff;
   389  	}
   390  	res = 0;
   391  	for(bit = 30; bit >= 0; bit--) {
   392  		if(v >= ((int64)div<<bit)) {
   393  			v = v - ((int64)div<<bit);
   394  			res += 1<<bit;
   395  		}
   396  	}
   397  	if(rem != nil)
   398  		*rem = v;
   399  	return res;
   400  }
   401  
   402  // Setting the max stack size doesn't really do anything for gccgo.
   403  
   404  uintptr runtime_maxstacksize = 1<<20; // enough until runtime.main sets it for real
   405  
   406  void memclrBytes(Slice)
   407       __asm__ (GOSYM_PREFIX "runtime.memclrBytes");
   408  
   409  void
   410  memclrBytes(Slice s)
   411  {
   412  	runtime_memclr(s.__values, s.__count);
   413  }