blob: 58e5bedf2f7634b3b97ea8110059f4bad7d2b513 [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// Copyright 2011 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 "runtime.h"
6#include "defs_GOOS_GOARCH.h"
7#include "os_GOOS.h"
8#include "signal_unix.h"
9#include "stack.h"
10#include "textflag.h"
11
12enum
13{
14 ESRCH = 3,
15 ENOTSUP = 91,
16
17 // From NetBSD's <sys/time.h>
18 CLOCK_REALTIME = 0,
19 CLOCK_VIRTUAL = 1,
20 CLOCK_PROF = 2,
21 CLOCK_MONOTONIC = 3
22};
23
24extern SigTab runtime·sigtab[];
25
26static Sigset sigset_none;
27static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
28
29extern void runtime·getcontext(UcontextT *context);
30extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
31extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
32extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
33extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
34extern int32 runtime·lwp_self(void);
35
36// From NetBSD's <sys/sysctl.h>
37#define CTL_HW 6
38#define HW_NCPU 3
39
40static int32
41getncpu(void)
42{
43 uint32 mib[2];
44 uint32 out;
45 int32 ret;
46 uintptr nout;
47
48 // Fetch hw.ncpu via sysctl.
49 mib[0] = CTL_HW;
50 mib[1] = HW_NCPU;
51 nout = sizeof out;
52 out = 0;
53 ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
54 if(ret >= 0)
55 return out;
56 else
57 return 1;
58}
59
60#pragma textflag NOSPLIT
61uintptr
62runtime·semacreate(void)
63{
64 return 1;
65}
66
67static void
68semasleep(void)
69{
70 int64 ns;
71 Timespec ts;
72
73 ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
74 g->m->scalararg[0] = 0;
75 g->m->scalararg[1] = 0;
76
77 // spin-mutex lock
78 while(runtime·xchg(&g->m->waitsemalock, 1))
79 runtime·osyield();
80
81 for(;;) {
82 // lock held
83 if(g->m->waitsemacount == 0) {
84 // sleep until semaphore != 0 or timeout.
85 // thrsleep unlocks m->waitsemalock.
86 if(ns < 0) {
87 // TODO(jsing) - potential deadlock!
88 //
89 // There is a potential deadlock here since we
90 // have to release the waitsemalock mutex
91 // before we call lwp_park() to suspend the
92 // thread. This allows another thread to
93 // release the lock and call lwp_unpark()
94 // before the thread is actually suspended.
95 // If this occurs the current thread will end
96 // up sleeping indefinitely. Unfortunately
97 // the NetBSD kernel does not appear to provide
98 // a mechanism for unlocking the userspace
99 // mutex once the thread is actually parked.
100 runtime·atomicstore(&g->m->waitsemalock, 0);
101 runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil);
102 } else {
103 ns = ns + runtime·nanotime();
104 // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
105 ts.tv_nsec = 0;
106 ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
107 // TODO(jsing) - potential deadlock!
108 // See above for details.
109 runtime·atomicstore(&g->m->waitsemalock, 0);
110 runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil);
111 }
112 // reacquire lock
113 while(runtime·xchg(&g->m->waitsemalock, 1))
114 runtime·osyield();
115 }
116
117 // lock held (again)
118 if(g->m->waitsemacount != 0) {
119 // semaphore is available.
120 g->m->waitsemacount--;
121 // spin-mutex unlock
122 runtime·atomicstore(&g->m->waitsemalock, 0);
123 g->m->scalararg[0] = 0; // semaphore acquired
124 return;
125 }
126
127 // semaphore not available.
128 // if there is a timeout, stop now.
129 // otherwise keep trying.
130 if(ns >= 0)
131 break;
132 }
133
134 // lock held but giving up
135 // spin-mutex unlock
136 runtime·atomicstore(&g->m->waitsemalock, 0);
137 g->m->scalararg[0] = -1;
138 return;
139}
140
141#pragma textflag NOSPLIT
142int32
143runtime·semasleep(int64 ns)
144{
145 int32 r;
146 void (*fn)(void);
147
148 g->m->scalararg[0] = (uint32)ns;
149 g->m->scalararg[1] = (uint32)(ns>>32);
150 fn = semasleep;
151 runtime·onM(&fn);
152 r = g->m->scalararg[0];
153 g->m->scalararg[0] = 0;
154 return r;
155}
156
157static void badsemawakeup(void);
158
159#pragma textflag NOSPLIT
160void
161runtime·semawakeup(M *mp)
162{
163 uint32 ret;
164 void (*fn)(void);
165 void *oldptr;
166 uintptr oldscalar;
167
168 // spin-mutex lock
169 while(runtime·xchg(&mp->waitsemalock, 1))
170 runtime·osyield();
171 mp->waitsemacount++;
172 // TODO(jsing) - potential deadlock, see semasleep() for details.
173 // Confirm that LWP is parked before unparking...
174 ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
175 if(ret != 0 && ret != ESRCH) {
176 // semawakeup can be called on signal stack.
177 // Save old ptrarg/scalararg so we can restore them.
178 oldptr = g->m->ptrarg[0];
179 oldscalar = g->m->scalararg[0];
180 g->m->ptrarg[0] = mp;
181 g->m->scalararg[0] = ret;
182 fn = badsemawakeup;
183 if(g == g->m->gsignal)
184 fn();
185 else
186 runtime·onM(&fn);
187 g->m->ptrarg[0] = oldptr;
188 g->m->scalararg[0] = oldscalar;
189 }
190 // spin-mutex unlock
191 runtime·atomicstore(&mp->waitsemalock, 0);
192}
193
194static void
195badsemawakeup(void)
196{
197 M *mp;
198 int32 ret;
199
200 mp = g->m->ptrarg[0];
201 g->m->ptrarg[0] = nil;
202 ret = g->m->scalararg[0];
203 g->m->scalararg[0] = 0;
204
205 runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
206}
207
208void
209runtime·newosproc(M *mp, void *stk)
210{
211 UcontextT uc;
212 int32 ret;
213
214 if(0) {
215 runtime·printf(
216 "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
217 stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
218 }
219
220 mp->tls[0] = mp->id; // so 386 asm can find it
221
222 runtime·getcontext(&uc);
223
224 uc.uc_flags = _UC_SIGMASK | _UC_CPU;
225 uc.uc_link = nil;
226 uc.uc_sigmask = sigset_all;
227
228 runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
229
230 ret = runtime·lwp_create(&uc, 0, &mp->procid);
231
232 if(ret < 0) {
233 runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
234 runtime·throw("runtime.newosproc");
235 }
236}
237
238void
239runtime·osinit(void)
240{
241 runtime·ncpu = getncpu();
242}
243
244#pragma textflag NOSPLIT
245void
246runtime·get_random_data(byte **rnd, int32 *rnd_len)
247{
248 #pragma dataflag NOPTR
249 static byte urandom_data[HashRandomBytes];
250 int32 fd;
251 fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
252 if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
253 *rnd = urandom_data;
254 *rnd_len = HashRandomBytes;
255 } else {
256 *rnd = nil;
257 *rnd_len = 0;
258 }
259 runtime·close(fd);
260}
261
262void
263runtime·goenvs(void)
264{
265 runtime·goenvs_unix();
266}
267
268// Called to initialize a new m (including the bootstrap m).
269// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
270void
271runtime·mpreinit(M *mp)
272{
273 mp->gsignal = runtime·malg(32*1024);
274 mp->gsignal->m = mp;
275}
276
277// Called to initialize a new m (including the bootstrap m).
278// Called on the new thread, can not allocate memory.
279void
280runtime·minit(void)
281{
282 g->m->procid = runtime·lwp_self();
283
284 // Initialize signal handling
285 runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
286 runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
287}
288
289// Called from dropm to undo the effect of an minit.
290void
291runtime·unminit(void)
292{
293 runtime·signalstack(nil, 0);
294}
295
296uintptr
297runtime·memlimit(void)
298{
299 return 0;
300}
301
302extern void runtime·sigtramp(void);
303
304typedef struct sigaction {
305 union {
306 void (*_sa_handler)(int32);
307 void (*_sa_sigaction)(int32, Siginfo*, void *);
308 } _sa_u; /* signal handler */
309 uint32 sa_mask[4]; /* signal mask to apply */
310 int32 sa_flags; /* see signal options below */
311} SigactionT;
312
313void
314runtime·setsig(int32 i, GoSighandler *fn, bool restart)
315{
316 SigactionT sa;
317
318 runtime·memclr((byte*)&sa, sizeof sa);
319 sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
320 if(restart)
321 sa.sa_flags |= SA_RESTART;
322 sa.sa_mask[0] = ~0U;
323 sa.sa_mask[1] = ~0U;
324 sa.sa_mask[2] = ~0U;
325 sa.sa_mask[3] = ~0U;
326 if (fn == runtime·sighandler)
327 fn = (void*)runtime·sigtramp;
328 sa._sa_u._sa_sigaction = (void*)fn;
329 runtime·sigaction(i, &sa, nil);
330}
331
332GoSighandler*
333runtime·getsig(int32 i)
334{
335 SigactionT sa;
336
337 runtime·memclr((byte*)&sa, sizeof sa);
338 runtime·sigaction(i, nil, &sa);
339 if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
340 return runtime·sighandler;
341 return (void*)sa._sa_u._sa_sigaction;
342}
343
344void
345runtime·signalstack(byte *p, int32 n)
346{
347 StackT st;
348
349 st.ss_sp = (void*)p;
350 st.ss_size = n;
351 st.ss_flags = 0;
352 if(p == nil)
353 st.ss_flags = SS_DISABLE;
354 runtime·sigaltstack(&st, nil);
355}
356
357void
358runtime·unblocksignals(void)
359{
360 runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
361}
362
363#pragma textflag NOSPLIT
364int8*
365runtime·signame(int32 sig)
366{
367 return runtime·sigtab[sig].name;
368}