~ubuntu-branches/ubuntu/utopic/gccgo-go/utopic

« back to all changes in this revision

Viewing changes to src/pkg/runtime/os_netbsd.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-27 09:18:55 UTC
  • Revision ID: package-import@ubuntu.com-20140127091855-zxfshmykfsyyw4b2
Tags: upstream-1.2
Import upstream version 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 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 "../../cmd/ld/textflag.h"
 
11
 
 
12
enum
 
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
 
 
24
extern SigTab runtime·sigtab[];
 
25
 
 
26
static Sigset sigset_none;
 
27
static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
 
28
 
 
29
extern void runtime·getcontext(UcontextT *context);
 
30
extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
 
31
extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
 
32
extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
 
33
extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
 
34
extern int32 runtime·lwp_self(void);
 
35
 
 
36
// From NetBSD's <sys/sysctl.h>
 
37
#define CTL_HW  6
 
38
#define HW_NCPU 3
 
39
 
 
40
static int32
 
41
getncpu(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
uintptr
 
61
runtime·semacreate(void)
 
62
{
 
63
        return 1;
 
64
}
 
65
 
 
66
#pragma textflag NOSPLIT
 
67
int32
 
68
runtime·semasleep(int64 ns)
 
69
{
 
70
        Timespec ts;
 
71
 
 
72
        // spin-mutex lock
 
73
        while(runtime·xchg(&m->waitsemalock, 1))
 
74
                runtime·osyield();
 
75
 
 
76
        for(;;) {
 
77
                // lock held
 
78
                if(m->waitsemacount == 0) {
 
79
                        // sleep until semaphore != 0 or timeout.
 
80
                        // thrsleep unlocks m->waitsemalock.
 
81
                        if(ns < 0) {
 
82
                                // TODO(jsing) - potential deadlock!
 
83
                                //
 
84
                                // There is a potential deadlock here since we
 
85
                                // have to release the waitsemalock mutex
 
86
                                // before we call lwp_park() to suspend the
 
87
                                // thread. This allows another thread to
 
88
                                // release the lock and call lwp_unpark()
 
89
                                // before the thread is actually suspended.
 
90
                                // If this occurs the current thread will end
 
91
                                // up sleeping indefinitely. Unfortunately
 
92
                                // the NetBSD kernel does not appear to provide
 
93
                                // a mechanism for unlocking the userspace
 
94
                                // mutex once the thread is actually parked.
 
95
                                runtime·atomicstore(&m->waitsemalock, 0);
 
96
                                runtime·lwp_park(nil, 0, &m->waitsemacount, nil);
 
97
                        } else {
 
98
                                ns = ns + runtime·nanotime();
 
99
                                // NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
 
100
                                ts.tv_nsec = 0;
 
101
                                ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
 
102
                                // TODO(jsing) - potential deadlock!
 
103
                                // See above for details.
 
104
                                runtime·atomicstore(&m->waitsemalock, 0);
 
105
                                runtime·lwp_park(&ts, 0, &m->waitsemacount, nil);
 
106
                        }
 
107
                        // reacquire lock
 
108
                        while(runtime·xchg(&m->waitsemalock, 1))
 
109
                                runtime·osyield();
 
110
                }
 
111
 
 
112
                // lock held (again)
 
113
                if(m->waitsemacount != 0) {
 
114
                        // semaphore is available.
 
115
                        m->waitsemacount--;
 
116
                        // spin-mutex unlock
 
117
                        runtime·atomicstore(&m->waitsemalock, 0);
 
118
                        return 0;  // semaphore acquired
 
119
                }
 
120
 
 
121
                // semaphore not available.
 
122
                // if there is a timeout, stop now.
 
123
                // otherwise keep trying.
 
124
                if(ns >= 0)
 
125
                        break;
 
126
        }
 
127
 
 
128
        // lock held but giving up
 
129
        // spin-mutex unlock
 
130
        runtime·atomicstore(&m->waitsemalock, 0);
 
131
        return -1;
 
132
}
 
133
 
 
134
void
 
135
runtime·semawakeup(M *mp)
 
136
{
 
137
        uint32 ret;
 
138
 
 
139
        // spin-mutex lock
 
140
        while(runtime·xchg(&mp->waitsemalock, 1))
 
141
                runtime·osyield();
 
142
        mp->waitsemacount++;
 
143
        // TODO(jsing) - potential deadlock, see semasleep() for details.
 
144
        // Confirm that LWP is parked before unparking...
 
145
        ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
 
146
        if(ret != 0 && ret != ESRCH)
 
147
                runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
 
148
        // spin-mutex unlock
 
149
        runtime·atomicstore(&mp->waitsemalock, 0);
 
150
}
 
151
 
 
152
void
 
153
runtime·newosproc(M *mp, void *stk)
 
154
{
 
155
        UcontextT uc;
 
156
        int32 ret;
 
157
 
 
158
        if(0) {
 
159
                runtime·printf(
 
160
                        "newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
 
161
                        stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
 
162
        }
 
163
 
 
164
        mp->tls[0] = mp->id;    // so 386 asm can find it
 
165
 
 
166
        runtime·getcontext(&uc);
 
167
        
 
168
        uc.uc_flags = _UC_SIGMASK | _UC_CPU;
 
169
        uc.uc_link = nil;
 
170
        uc.uc_sigmask = sigset_all;
 
171
 
 
172
        runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
 
173
 
 
174
        ret = runtime·lwp_create(&uc, 0, &mp->procid);
 
175
 
 
176
        if(ret < 0) {
 
177
                runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
 
178
                runtime·throw("runtime.newosproc");
 
179
        }
 
180
}
 
181
 
 
182
void
 
183
runtime·osinit(void)
 
184
{
 
185
        runtime·ncpu = getncpu();
 
186
}
 
187
 
 
188
void
 
189
runtime·get_random_data(byte **rnd, int32 *rnd_len)
 
190
{
 
191
        static byte urandom_data[HashRandomBytes];
 
192
        int32 fd;
 
193
        fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
 
194
        if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
 
195
                *rnd = urandom_data;
 
196
                *rnd_len = HashRandomBytes;
 
197
        } else {
 
198
                *rnd = nil;
 
199
                *rnd_len = 0;
 
200
        }
 
201
        runtime·close(fd);
 
202
}
 
203
 
 
204
void
 
205
runtime·goenvs(void)
 
206
{
 
207
        runtime·goenvs_unix();
 
208
}
 
209
 
 
210
// Called to initialize a new m (including the bootstrap m).
 
211
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
 
212
void
 
213
runtime·mpreinit(M *mp)
 
214
{
 
215
        mp->gsignal = runtime·malg(32*1024);
 
216
}
 
217
 
 
218
// Called to initialize a new m (including the bootstrap m).
 
219
// Called on the new thread, can not allocate memory.
 
220
void
 
221
runtime·minit(void)
 
222
{
 
223
        m->procid = runtime·lwp_self();
 
224
 
 
225
        // Initialize signal handling
 
226
        runtime·signalstack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
 
227
        runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
 
228
}
 
229
 
 
230
// Called from dropm to undo the effect of an minit.
 
231
void
 
232
runtime·unminit(void)
 
233
{
 
234
        runtime·signalstack(nil, 0);
 
235
}
 
236
 
 
237
void
 
238
runtime·sigpanic(void)
 
239
{
 
240
        switch(g->sig) {
 
241
        case SIGBUS:
 
242
                if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
 
243
                        if(g->sigpc == 0)
 
244
                                runtime·panicstring("call of nil func value");
 
245
                        runtime·panicstring("invalid memory address or nil pointer dereference");
 
246
                }
 
247
                runtime·printf("unexpected fault address %p\n", g->sigcode1);
 
248
                runtime·throw("fault");
 
249
        case SIGSEGV:
 
250
                if((g->sigcode0 == 0 || g->sigcode0 == SEGV_MAPERR || g->sigcode0 == SEGV_ACCERR) && g->sigcode1 < 0x1000) {
 
251
                        if(g->sigpc == 0)
 
252
                                runtime·panicstring("call of nil func value");
 
253
                        runtime·panicstring("invalid memory address or nil pointer dereference");
 
254
                }
 
255
                runtime·printf("unexpected fault address %p\n", g->sigcode1);
 
256
                runtime·throw("fault");
 
257
        case SIGFPE:
 
258
                switch(g->sigcode0) {
 
259
                case FPE_INTDIV:
 
260
                        runtime·panicstring("integer divide by zero");
 
261
                case FPE_INTOVF:
 
262
                        runtime·panicstring("integer overflow");
 
263
                }
 
264
                runtime·panicstring("floating point error");
 
265
        }
 
266
        runtime·panicstring(runtime·sigtab[g->sig].name);
 
267
}
 
268
 
 
269
uintptr
 
270
runtime·memlimit(void)
 
271
{
 
272
        return 0;
 
273
}
 
274
 
 
275
extern void runtime·sigtramp(void);
 
276
 
 
277
typedef struct sigaction {
 
278
        union {
 
279
                void    (*_sa_handler)(int32);
 
280
                void    (*_sa_sigaction)(int32, Siginfo*, void *);
 
281
        } _sa_u;                        /* signal handler */
 
282
        uint32  sa_mask[4];             /* signal mask to apply */
 
283
        int32   sa_flags;               /* see signal options below */
 
284
} Sigaction;
 
285
 
 
286
void
 
287
runtime·setsig(int32 i, GoSighandler *fn, bool restart)
 
288
{
 
289
        Sigaction sa;
 
290
 
 
291
        runtime·memclr((byte*)&sa, sizeof sa);
 
292
        sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
 
293
        if(restart)
 
294
                sa.sa_flags |= SA_RESTART;
 
295
        sa.sa_mask[0] = ~0U;
 
296
        sa.sa_mask[1] = ~0U;
 
297
        sa.sa_mask[2] = ~0U;
 
298
        sa.sa_mask[3] = ~0U;
 
299
        if (fn == runtime·sighandler)
 
300
                fn = (void*)runtime·sigtramp;
 
301
        sa._sa_u._sa_sigaction = (void*)fn;
 
302
        runtime·sigaction(i, &sa, nil);
 
303
}
 
304
 
 
305
GoSighandler*
 
306
runtime·getsig(int32 i)
 
307
{
 
308
        Sigaction sa;
 
309
 
 
310
        runtime·memclr((byte*)&sa, sizeof sa);
 
311
        runtime·sigaction(i, nil, &sa);
 
312
        if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
 
313
                return runtime·sighandler;
 
314
        return (void*)sa._sa_u._sa_sigaction;
 
315
}
 
316
 
 
317
void
 
318
runtime·signalstack(byte *p, int32 n)
 
319
{
 
320
        StackT st;
 
321
 
 
322
        st.ss_sp = (void*)p;
 
323
        st.ss_size = n;
 
324
        st.ss_flags = 0;
 
325
        if(p == nil)
 
326
                st.ss_flags = SS_DISABLE;
 
327
        runtime·sigaltstack(&st, nil);
 
328
}