github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/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 "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 #pragma textflag NOSPLIT 61 uintptr 62 runtime·semacreate(void) 63 { 64 return 1; 65 } 66 67 static void 68 semasleep(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 142 int32 143 runtime·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 157 static void badsemawakeup(void); 158 159 #pragma textflag NOSPLIT 160 void 161 runtime·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 194 static void 195 badsemawakeup(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 208 void 209 runtime·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 238 void 239 runtime·osinit(void) 240 { 241 runtime·ncpu = getncpu(); 242 } 243 244 #pragma textflag NOSPLIT 245 void 246 runtime·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 262 void 263 runtime·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. 270 void 271 runtime·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. 279 void 280 runtime·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. 290 void 291 runtime·unminit(void) 292 { 293 runtime·signalstack(nil, 0); 294 } 295 296 uintptr 297 runtime·memlimit(void) 298 { 299 return 0; 300 } 301 302 extern void runtime·sigtramp(void); 303 304 typedef 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 313 void 314 runtime·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 332 GoSighandler* 333 runtime·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 344 void 345 runtime·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 357 void 358 runtime·unblocksignals(void) 359 { 360 runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); 361 } 362 363 #pragma textflag NOSPLIT 364 int8* 365 runtime·signame(int32 sig) 366 { 367 return runtime·sigtab[sig].name; 368 }