github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/os_netbsd.c (about) 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 }