PR target/61794
[official-gcc.git] / libgo / runtime / runtime.c
blob1678a45d40a5ba38eb1af7f6a085c6970c2eb296
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.
5 #include <signal.h>
6 #include <unistd.h>
8 #include "config.h"
10 #include "runtime.h"
11 #include "array.h"
13 // The GOTRACEBACK environment variable controls the
14 // behavior of a Go program that is crashing and exiting.
15 // GOTRACEBACK=0 suppress all tracebacks
16 // GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
17 // GOTRACEBACK=2 show tracebacks including runtime frames
18 // GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
19 int32
20 runtime_gotraceback(bool *crash)
22 const byte *p;
24 if(crash != nil)
25 *crash = false;
26 p = runtime_getenv("GOTRACEBACK");
27 if(p == nil || p[0] == '\0')
28 return 1; // default is on
29 if(runtime_strcmp((const char *)p, "crash") == 0) {
30 if(crash != nil)
31 *crash = true;
32 return 2; // extra information
34 return runtime_atoi(p);
37 static int32 argc;
38 static byte** argv;
40 extern Slice os_Args __asm__ (GOSYM_PREFIX "os.Args");
41 extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs");
43 void (*runtime_sysargs)(int32, uint8**);
45 void
46 runtime_args(int32 c, byte **v)
48 argc = c;
49 argv = v;
50 if(runtime_sysargs != nil)
51 runtime_sysargs(c, v);
54 byte*
55 runtime_progname()
57 return argc == 0 ? nil : argv[0];
60 void
61 runtime_goargs(void)
63 String *s;
64 int32 i;
66 // for windows implementation see "os" package
67 if(Windows)
68 return;
70 s = runtime_malloc(argc*sizeof s[0]);
71 for(i=0; i<argc; i++)
72 s[i] = runtime_gostringnocopy((const byte*)argv[i]);
73 os_Args.__values = (void*)s;
74 os_Args.__count = argc;
75 os_Args.__capacity = argc;
78 void
79 runtime_goenvs_unix(void)
81 String *s;
82 int32 i, n;
84 for(n=0; argv[argc+1+n] != 0; n++)
87 s = runtime_malloc(n*sizeof s[0]);
88 for(i=0; i<n; i++)
89 s[i] = runtime_gostringnocopy(argv[argc+1+i]);
90 syscall_Envs.__values = (void*)s;
91 syscall_Envs.__count = n;
92 syscall_Envs.__capacity = n;
95 int32
96 runtime_atoi(const byte *p)
98 int32 n;
100 n = 0;
101 while('0' <= *p && *p <= '9')
102 n = n*10 + *p++ - '0';
103 return n;
106 static struct root_list runtime_roots =
107 { nil,
108 { { &syscall_Envs, sizeof syscall_Envs },
109 { &os_Args, sizeof os_Args },
110 { nil, 0 } },
113 static void
114 TestAtomic64(void)
116 uint64 z64, x64;
118 z64 = 42;
119 x64 = 0;
120 PREFETCH(&z64);
121 if(runtime_cas64(&z64, x64, 1))
122 runtime_throw("cas64 failed");
123 if(x64 != 0)
124 runtime_throw("cas64 failed");
125 x64 = 42;
126 if(!runtime_cas64(&z64, x64, 1))
127 runtime_throw("cas64 failed");
128 if(x64 != 42 || z64 != 1)
129 runtime_throw("cas64 failed");
130 if(runtime_atomicload64(&z64) != 1)
131 runtime_throw("load64 failed");
132 runtime_atomicstore64(&z64, (1ull<<40)+1);
133 if(runtime_atomicload64(&z64) != (1ull<<40)+1)
134 runtime_throw("store64 failed");
135 if(runtime_xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
136 runtime_throw("xadd64 failed");
137 if(runtime_atomicload64(&z64) != (2ull<<40)+2)
138 runtime_throw("xadd64 failed");
139 if(runtime_xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
140 runtime_throw("xchg64 failed");
141 if(runtime_atomicload64(&z64) != (3ull<<40)+3)
142 runtime_throw("xchg64 failed");
145 void
146 runtime_check(void)
148 __go_register_gc_roots(&runtime_roots);
150 TestAtomic64();
153 uint32
154 runtime_fastrand1(void)
156 M *m;
157 uint32 x;
159 m = runtime_m();
160 x = m->fastrand;
161 x += x;
162 if(x & 0x80000000L)
163 x ^= 0x88888eefUL;
164 m->fastrand = x;
165 return x;
168 int64
169 runtime_cputicks(void)
171 #if defined(__386__) || defined(__x86_64__)
172 uint32 low, high;
173 asm("rdtsc" : "=a" (low), "=d" (high));
174 return (int64)(((uint64)high << 32) | (uint64)low);
175 #else
176 // FIXME: implement for other processors.
177 return 0;
178 #endif
181 bool
182 runtime_showframe(String s, bool current)
184 static int32 traceback = -1;
186 if(current && runtime_m()->throwing > 0)
187 return 1;
188 if(traceback < 0)
189 traceback = runtime_gotraceback(nil);
190 return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
193 static Lock ticksLock;
194 static int64 ticks;
196 int64
197 runtime_tickspersecond(void)
199 int64 res, t0, t1, c0, c1;
201 res = (int64)runtime_atomicload64((uint64*)&ticks);
202 if(res != 0)
203 return ticks;
204 runtime_lock(&ticksLock);
205 res = ticks;
206 if(res == 0) {
207 t0 = runtime_nanotime();
208 c0 = runtime_cputicks();
209 runtime_usleep(100*1000);
210 t1 = runtime_nanotime();
211 c1 = runtime_cputicks();
212 if(t1 == t0)
213 t1++;
214 res = (c1-c0)*1000*1000*1000/(t1-t0);
215 if(res == 0)
216 res++;
217 runtime_atomicstore64((uint64*)&ticks, res);
219 runtime_unlock(&ticksLock);
220 return res;
223 // Called to initialize a new m (including the bootstrap m).
224 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
225 void
226 runtime_mpreinit(M *mp)
228 mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize); // OS X wants >=8K, Linux >=2K
231 // Called to initialize a new m (including the bootstrap m).
232 // Called on the new thread, can not allocate memory.
233 void
234 runtime_minit(void)
236 M* m;
237 sigset_t sigs;
239 // Initialize signal handling.
240 m = runtime_m();
241 runtime_signalstack(m->gsignalstack, m->gsignalstacksize);
242 if (sigemptyset(&sigs) != 0)
243 runtime_throw("sigemptyset");
244 pthread_sigmask(SIG_SETMASK, &sigs, nil);
247 // Called from dropm to undo the effect of an minit.
248 void
249 runtime_unminit(void)
251 runtime_signalstack(nil, 0);
255 void
256 runtime_signalstack(byte *p, int32 n)
258 stack_t st;
260 st.ss_sp = p;
261 st.ss_size = n;
262 st.ss_flags = 0;
263 if(p == nil)
264 st.ss_flags = SS_DISABLE;
265 if(sigaltstack(&st, nil) < 0)
266 *(int *)0xf1 = 0xf1;
269 DebugVars runtime_debug;
271 static struct {
272 const char* name;
273 int32* value;
274 } dbgvar[] = {
275 {"allocfreetrace", &runtime_debug.allocfreetrace},
276 {"efence", &runtime_debug.efence},
277 {"gctrace", &runtime_debug.gctrace},
278 {"scheddetail", &runtime_debug.scheddetail},
279 {"schedtrace", &runtime_debug.schedtrace},
282 void
283 runtime_parsedebugvars(void)
285 const byte *p;
286 intgo i, n;
288 p = runtime_getenv("GODEBUG");
289 if(p == nil)
290 return;
291 for(;;) {
292 for(i=0; i<(intgo)nelem(dbgvar); i++) {
293 n = runtime_findnull((const byte*)dbgvar[i].name);
294 if(runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=')
295 *dbgvar[i].value = runtime_atoi(p+n+1);
297 p = (const byte *)runtime_strstr((const char *)p, ",");
298 if(p == nil)
299 break;
300 p++;
304 // Poor mans 64-bit division.
305 // This is a very special function, do not use it if you are not sure what you are doing.
306 // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
307 // Handles overflow in a time-specific manner.
308 int32
309 runtime_timediv(int64 v, int32 div, int32 *rem)
311 int32 res, bit;
313 if(v >= (int64)div*0x7fffffffLL) {
314 if(rem != nil)
315 *rem = 0;
316 return 0x7fffffff;
318 res = 0;
319 for(bit = 30; bit >= 0; bit--) {
320 if(v >= ((int64)div<<bit)) {
321 v = v - ((int64)div<<bit);
322 res += 1<<bit;
325 if(rem != nil)
326 *rem = v;
327 return res;
330 // Setting the max stack size doesn't really do anything for gccgo.
332 uintptr runtime_maxstacksize = 1<<20; // enough until runtime.main sets it for real
334 void memclrBytes(Slice)
335 __asm__ (GOSYM_PREFIX "runtime.memclrBytes");
337 void
338 memclrBytes(Slice s)
340 runtime_memclr(s.__values, s.__count);