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 "array.h"
12 #include "go-panic.h"
13 
14 // The GOTRACEBACK environment variable controls the
15 // behavior of a Go program that is crashing and exiting.
16 //	GOTRACEBACK=0   suppress all tracebacks
17 //	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
18 //	GOTRACEBACK=2   show tracebacks including runtime frames
19 //	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
20 int32
runtime_gotraceback(bool * crash)21 runtime_gotraceback(bool *crash)
22 {
23 	const byte *p;
24 
25 	if(crash != nil)
26 		*crash = false;
27 	p = runtime_getenv("GOTRACEBACK");
28 	if(p == nil || p[0] == '\0')
29 		return 1;	// default is on
30 	if(runtime_strcmp((const char *)p, "crash") == 0) {
31 		if(crash != nil)
32 			*crash = true;
33 		return 2;	// extra information
34 	}
35 	return runtime_atoi(p);
36 }
37 
38 static int32	argc;
39 static byte**	argv;
40 
41 extern Slice os_Args __asm__ (GOSYM_PREFIX "os.Args");
42 extern Slice syscall_Envs __asm__ (GOSYM_PREFIX "syscall.Envs");
43 
44 void (*runtime_sysargs)(int32, uint8**);
45 
46 void
runtime_args(int32 c,byte ** v)47 runtime_args(int32 c, byte **v)
48 {
49 	argc = c;
50 	argv = v;
51 	if(runtime_sysargs != nil)
52 		runtime_sysargs(c, v);
53 }
54 
55 byte*
runtime_progname()56 runtime_progname()
57 {
58   return argc == 0 ? nil : argv[0];
59 }
60 
61 // Information about what cpu features are available.
62 // Set on startup in asm_{x86/amd64}.s.
63 uint32 runtime_cpuid_ecx;
64 uint32 runtime_cpuid_edx;
65 
66 void
runtime_goargs(void)67 runtime_goargs(void)
68 {
69 	String *s;
70 	int32 i;
71 
72 	// for windows implementation see "os" package
73 	if(Windows)
74 		return;
75 
76 	s = runtime_malloc(argc*sizeof s[0]);
77 	for(i=0; i<argc; i++)
78 		s[i] = runtime_gostringnocopy((const byte*)argv[i]);
79 	os_Args.__values = (void*)s;
80 	os_Args.__count = argc;
81 	os_Args.__capacity = argc;
82 }
83 
84 void
runtime_goenvs_unix(void)85 runtime_goenvs_unix(void)
86 {
87 	String *s;
88 	int32 i, n;
89 
90 	for(n=0; argv[argc+1+n] != 0; n++)
91 		;
92 
93 	s = runtime_malloc(n*sizeof s[0]);
94 	for(i=0; i<n; i++)
95 		s[i] = runtime_gostringnocopy(argv[argc+1+i]);
96 	syscall_Envs.__values = (void*)s;
97 	syscall_Envs.__count = n;
98 	syscall_Envs.__capacity = n;
99 }
100 
101 int32
runtime_atoi(const byte * p)102 runtime_atoi(const byte *p)
103 {
104 	int32 n;
105 
106 	n = 0;
107 	while('0' <= *p && *p <= '9')
108 		n = n*10 + *p++ - '0';
109 	return n;
110 }
111 
112 static struct root_list runtime_roots =
113 { nil,
114   { { &syscall_Envs, sizeof syscall_Envs },
115     { &os_Args, sizeof os_Args },
116     { nil, 0 } },
117 };
118 
119 static void
TestAtomic64(void)120 TestAtomic64(void)
121 {
122 	uint64 z64, x64;
123 
124 	z64 = 42;
125 	x64 = 0;
126 	PREFETCH(&z64);
127 	if(runtime_cas64(&z64, &x64, 1))
128 		runtime_throw("cas64 failed");
129 	if(x64 != 42)
130 		runtime_throw("cas64 failed");
131 	if(!runtime_cas64(&z64, &x64, 1))
132 		runtime_throw("cas64 failed");
133 	if(x64 != 42 || z64 != 1)
134 		runtime_throw("cas64 failed");
135 	if(runtime_atomicload64(&z64) != 1)
136 		runtime_throw("load64 failed");
137 	runtime_atomicstore64(&z64, (1ull<<40)+1);
138 	if(runtime_atomicload64(&z64) != (1ull<<40)+1)
139 		runtime_throw("store64 failed");
140 	if(runtime_xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
141 		runtime_throw("xadd64 failed");
142 	if(runtime_atomicload64(&z64) != (2ull<<40)+2)
143 		runtime_throw("xadd64 failed");
144 	if(runtime_xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
145 		runtime_throw("xchg64 failed");
146 	if(runtime_atomicload64(&z64) != (3ull<<40)+3)
147 		runtime_throw("xchg64 failed");
148 }
149 
150 void
runtime_check(void)151 runtime_check(void)
152 {
153 	__go_register_gc_roots(&runtime_roots);
154 
155 	TestAtomic64();
156 }
157 
158 uint32
runtime_fastrand1(void)159 runtime_fastrand1(void)
160 {
161 	M *m;
162 	uint32 x;
163 
164 	m = runtime_m();
165 	x = m->fastrand;
166 	x += x;
167 	if(x & 0x80000000L)
168 		x ^= 0x88888eefUL;
169 	m->fastrand = x;
170 	return x;
171 }
172 
173 int64
runtime_cputicks(void)174 runtime_cputicks(void)
175 {
176 #if defined(__386__) || defined(__x86_64__)
177   uint32 low, high;
178   asm("rdtsc" : "=a" (low), "=d" (high));
179   return (int64)(((uint64)high << 32) | (uint64)low);
180 #else
181   // FIXME: implement for other processors.
182   return 0;
183 #endif
184 }
185 
186 bool
runtime_showframe(String s,bool current)187 runtime_showframe(String s, bool current)
188 {
189 	static int32 traceback = -1;
190 
191 	if(current && runtime_m()->throwing > 0)
192 		return 1;
193 	if(traceback < 0)
194 		traceback = runtime_gotraceback(nil);
195 	return traceback > 1 || (__builtin_memchr(s.str, '.', s.len) != nil && __builtin_memcmp(s.str, "runtime.", 7) != 0);
196 }
197 
198 static Lock ticksLock;
199 static int64 ticks;
200 
201 int64
runtime_tickspersecond(void)202 runtime_tickspersecond(void)
203 {
204 	int64 res, t0, t1, c0, c1;
205 
206 	res = (int64)runtime_atomicload64((uint64*)&ticks);
207 	if(res != 0)
208 		return ticks;
209 	runtime_lock(&ticksLock);
210 	res = ticks;
211 	if(res == 0) {
212 		t0 = runtime_nanotime();
213 		c0 = runtime_cputicks();
214 		runtime_usleep(100*1000);
215 		t1 = runtime_nanotime();
216 		c1 = runtime_cputicks();
217 		if(t1 == t0)
218 			t1++;
219 		res = (c1-c0)*1000*1000*1000/(t1-t0);
220 		if(res == 0)
221 			res++;
222 		runtime_atomicstore64((uint64*)&ticks, res);
223 	}
224 	runtime_unlock(&ticksLock);
225 	return res;
226 }
227 
228 int64 runtime_pprof_runtime_cyclesPerSecond(void)
229      __asm__ (GOSYM_PREFIX "runtime_pprof.runtime_cyclesPerSecond");
230 
231 int64
runtime_pprof_runtime_cyclesPerSecond(void)232 runtime_pprof_runtime_cyclesPerSecond(void)
233 {
234 	return runtime_tickspersecond();
235 }
236 
237 // Called to initialize a new m (including the bootstrap m).
238 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
239 void
runtime_mpreinit(M * mp)240 runtime_mpreinit(M *mp)
241 {
242 	mp->gsignal = runtime_malg(32*1024, &mp->gsignalstack, &mp->gsignalstacksize);	// OS X wants >=8K, Linux >=2K
243 }
244 
245 // Called to initialize a new m (including the bootstrap m).
246 // Called on the new thread, can not allocate memory.
247 void
runtime_minit(void)248 runtime_minit(void)
249 {
250 	M* m;
251 	sigset_t sigs;
252 
253 	// Initialize signal handling.
254 	m = runtime_m();
255 	runtime_signalstack(m->gsignalstack, m->gsignalstacksize);
256 	if (sigemptyset(&sigs) != 0)
257 		runtime_throw("sigemptyset");
258 	sigprocmask(SIG_SETMASK, &sigs, nil);
259 }
260 
261 // Called from dropm to undo the effect of an minit.
262 void
runtime_unminit(void)263 runtime_unminit(void)
264 {
265 	runtime_signalstack(nil, 0);
266 }
267 
268 
269 void
runtime_signalstack(byte * p,int32 n)270 runtime_signalstack(byte *p, int32 n)
271 {
272 	stack_t st;
273 
274 	st.ss_sp = p;
275 	st.ss_size = n;
276 	st.ss_flags = 0;
277 	if(p == nil)
278 		st.ss_flags = SS_DISABLE;
279 	if(sigaltstack(&st, nil) < 0)
280 		*(int *)0xf1 = 0xf1;
281 }
282