github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/os_darwin.c (about) 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 "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 extern SigTab runtime·sigtab[]; 13 14 static Sigset sigset_none; 15 static Sigset sigset_all = ~(Sigset)0; 16 17 static void 18 unimplemented(int8 *name) 19 { 20 runtime·prints(name); 21 runtime·prints(" not implemented\n"); 22 *(int32*)1231 = 1231; 23 } 24 25 #pragma textflag NOSPLIT 26 void 27 runtime·semawakeup(M *mp) 28 { 29 runtime·mach_semrelease(mp->waitsema); 30 } 31 32 static void 33 semacreate(void) 34 { 35 g->m->scalararg[0] = runtime·mach_semcreate(); 36 } 37 38 #pragma textflag NOSPLIT 39 uintptr 40 runtime·semacreate(void) 41 { 42 uintptr x; 43 void (*fn)(void); 44 45 fn = semacreate; 46 runtime·onM(&fn); 47 x = g->m->scalararg[0]; 48 g->m->scalararg[0] = 0; 49 return x; 50 } 51 52 // BSD interface for threading. 53 void 54 runtime·osinit(void) 55 { 56 // bsdthread_register delayed until end of goenvs so that we 57 // can look at the environment first. 58 59 // Use sysctl to fetch hw.ncpu. 60 uint32 mib[2]; 61 uint32 out; 62 int32 ret; 63 uintptr nout; 64 65 mib[0] = 6; 66 mib[1] = 3; 67 nout = sizeof out; 68 out = 0; 69 ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0); 70 if(ret >= 0) 71 runtime·ncpu = out; 72 } 73 74 #pragma textflag NOSPLIT 75 void 76 runtime·get_random_data(byte **rnd, int32 *rnd_len) 77 { 78 #pragma dataflag NOPTR 79 static byte urandom_data[HashRandomBytes]; 80 int32 fd; 81 fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0); 82 if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) { 83 *rnd = urandom_data; 84 *rnd_len = HashRandomBytes; 85 } else { 86 *rnd = nil; 87 *rnd_len = 0; 88 } 89 runtime·close(fd); 90 } 91 92 void 93 runtime·goenvs(void) 94 { 95 runtime·goenvs_unix(); 96 97 // Register our thread-creation callback (see sys_darwin_{amd64,386}.s) 98 // but only if we're not using cgo. If we are using cgo we need 99 // to let the C pthread library install its own thread-creation callback. 100 if(!runtime·iscgo) { 101 if(runtime·bsdthread_register() != 0) { 102 if(runtime·getenv("DYLD_INSERT_LIBRARIES")) 103 runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)"); 104 runtime·throw("runtime: bsdthread_register error"); 105 } 106 } 107 108 } 109 110 void 111 runtime·newosproc(M *mp, void *stk) 112 { 113 int32 errno; 114 Sigset oset; 115 116 mp->tls[0] = mp->id; // so 386 asm can find it 117 if(0){ 118 runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n", 119 stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp); 120 } 121 122 runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset); 123 errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart); 124 runtime·sigprocmask(SIG_SETMASK, &oset, nil); 125 126 if(errno < 0) { 127 runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno); 128 runtime·throw("runtime.newosproc"); 129 } 130 } 131 132 // Called to initialize a new m (including the bootstrap m). 133 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 134 void 135 runtime·mpreinit(M *mp) 136 { 137 mp->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K 138 mp->gsignal->m = mp; 139 } 140 141 // Called to initialize a new m (including the bootstrap m). 142 // Called on the new thread, can not allocate memory. 143 void 144 runtime·minit(void) 145 { 146 // Initialize signal handling. 147 runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024); 148 149 runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); 150 } 151 152 // Called from dropm to undo the effect of an minit. 153 void 154 runtime·unminit(void) 155 { 156 runtime·signalstack(nil, 0); 157 } 158 159 // Mach IPC, to get at semaphores 160 // Definitions are in /usr/include/mach on a Mac. 161 162 static void 163 macherror(int32 r, int8 *fn) 164 { 165 runtime·prints("mach error "); 166 runtime·prints(fn); 167 runtime·prints(": "); 168 runtime·printint(r); 169 runtime·prints("\n"); 170 runtime·throw("mach error"); 171 } 172 173 enum 174 { 175 DebugMach = 0 176 }; 177 178 static MachNDR zerondr; 179 180 #define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8)) 181 182 static int32 183 mach_msg(MachHeader *h, 184 int32 op, 185 uint32 send_size, 186 uint32 rcv_size, 187 uint32 rcv_name, 188 uint32 timeout, 189 uint32 notify) 190 { 191 // TODO: Loop on interrupt. 192 return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify); 193 } 194 195 // Mach RPC (MIG) 196 197 enum 198 { 199 MinMachMsg = 48, 200 Reply = 100, 201 }; 202 203 #pragma pack on 204 typedef struct CodeMsg CodeMsg; 205 struct CodeMsg 206 { 207 MachHeader h; 208 MachNDR NDR; 209 int32 code; 210 }; 211 #pragma pack off 212 213 static int32 214 machcall(MachHeader *h, int32 maxsize, int32 rxsize) 215 { 216 uint32 *p; 217 int32 i, ret, id; 218 uint32 port; 219 CodeMsg *c; 220 221 if((port = g->m->machport) == 0){ 222 port = runtime·mach_reply_port(); 223 g->m->machport = port; 224 } 225 226 h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); 227 h->msgh_local_port = port; 228 h->msgh_reserved = 0; 229 id = h->msgh_id; 230 231 if(DebugMach){ 232 p = (uint32*)h; 233 runtime·prints("send:\t"); 234 for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ 235 runtime·prints(" "); 236 runtime·printpointer((void*)p[i]); 237 if(i%8 == 7) 238 runtime·prints("\n\t"); 239 } 240 if(i%8) 241 runtime·prints("\n"); 242 } 243 244 ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG, 245 h->msgh_size, maxsize, port, 0, 0); 246 if(ret != 0){ 247 if(DebugMach){ 248 runtime·prints("mach_msg error "); 249 runtime·printint(ret); 250 runtime·prints("\n"); 251 } 252 return ret; 253 } 254 255 if(DebugMach){ 256 p = (uint32*)h; 257 runtime·prints("recv:\t"); 258 for(i=0; i<h->msgh_size/sizeof(p[0]); i++){ 259 runtime·prints(" "); 260 runtime·printpointer((void*)p[i]); 261 if(i%8 == 7) 262 runtime·prints("\n\t"); 263 } 264 if(i%8) 265 runtime·prints("\n"); 266 } 267 268 if(h->msgh_id != id+Reply){ 269 if(DebugMach){ 270 runtime·prints("mach_msg reply id mismatch "); 271 runtime·printint(h->msgh_id); 272 runtime·prints(" != "); 273 runtime·printint(id+Reply); 274 runtime·prints("\n"); 275 } 276 return -303; // MIG_REPLY_MISMATCH 277 } 278 279 // Look for a response giving the return value. 280 // Any call can send this back with an error, 281 // and some calls only have return values so they 282 // send it back on success too. I don't quite see how 283 // you know it's one of these and not the full response 284 // format, so just look if the message is right. 285 c = (CodeMsg*)h; 286 if(h->msgh_size == sizeof(CodeMsg) 287 && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){ 288 if(DebugMach){ 289 runtime·prints("mig result "); 290 runtime·printint(c->code); 291 runtime·prints("\n"); 292 } 293 return c->code; 294 } 295 296 if(h->msgh_size != rxsize){ 297 if(DebugMach){ 298 runtime·prints("mach_msg reply size mismatch "); 299 runtime·printint(h->msgh_size); 300 runtime·prints(" != "); 301 runtime·printint(rxsize); 302 runtime·prints("\n"); 303 } 304 return -307; // MIG_ARRAY_TOO_LARGE 305 } 306 307 return 0; 308 } 309 310 311 // Semaphores! 312 313 enum 314 { 315 Tmach_semcreate = 3418, 316 Rmach_semcreate = Tmach_semcreate + Reply, 317 318 Tmach_semdestroy = 3419, 319 Rmach_semdestroy = Tmach_semdestroy + Reply, 320 321 // Mach calls that get interrupted by Unix signals 322 // return this error code. We retry them. 323 KERN_ABORTED = 14, 324 KERN_OPERATION_TIMED_OUT = 49, 325 }; 326 327 typedef struct Tmach_semcreateMsg Tmach_semcreateMsg; 328 typedef struct Rmach_semcreateMsg Rmach_semcreateMsg; 329 typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg; 330 // Rmach_semdestroyMsg = CodeMsg 331 332 #pragma pack on 333 struct Tmach_semcreateMsg 334 { 335 MachHeader h; 336 MachNDR ndr; 337 int32 policy; 338 int32 value; 339 }; 340 341 struct Rmach_semcreateMsg 342 { 343 MachHeader h; 344 MachBody body; 345 MachPort semaphore; 346 }; 347 348 struct Tmach_semdestroyMsg 349 { 350 MachHeader h; 351 MachBody body; 352 MachPort semaphore; 353 }; 354 #pragma pack off 355 356 uint32 357 runtime·mach_semcreate(void) 358 { 359 union { 360 Tmach_semcreateMsg tx; 361 Rmach_semcreateMsg rx; 362 uint8 pad[MinMachMsg]; 363 } m; 364 int32 r; 365 366 m.tx.h.msgh_bits = 0; 367 m.tx.h.msgh_size = sizeof(m.tx); 368 m.tx.h.msgh_remote_port = runtime·mach_task_self(); 369 m.tx.h.msgh_id = Tmach_semcreate; 370 m.tx.ndr = zerondr; 371 372 m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO 373 m.tx.value = 0; 374 375 while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){ 376 if(r == KERN_ABORTED) // interrupted 377 continue; 378 macherror(r, "semaphore_create"); 379 } 380 if(m.rx.body.msgh_descriptor_count != 1) 381 unimplemented("mach_semcreate desc count"); 382 return m.rx.semaphore.name; 383 } 384 385 void 386 runtime·mach_semdestroy(uint32 sem) 387 { 388 union { 389 Tmach_semdestroyMsg tx; 390 uint8 pad[MinMachMsg]; 391 } m; 392 int32 r; 393 394 m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX; 395 m.tx.h.msgh_size = sizeof(m.tx); 396 m.tx.h.msgh_remote_port = runtime·mach_task_self(); 397 m.tx.h.msgh_id = Tmach_semdestroy; 398 m.tx.body.msgh_descriptor_count = 1; 399 m.tx.semaphore.name = sem; 400 m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND; 401 m.tx.semaphore.type = 0; 402 403 while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){ 404 if(r == KERN_ABORTED) // interrupted 405 continue; 406 macherror(r, "semaphore_destroy"); 407 } 408 } 409 410 // The other calls have simple system call traps in sys_darwin_{amd64,386}.s 411 int32 runtime·mach_semaphore_wait(uint32 sema); 412 int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec); 413 int32 runtime·mach_semaphore_signal(uint32 sema); 414 int32 runtime·mach_semaphore_signal_all(uint32 sema); 415 416 static void 417 semasleep(void) 418 { 419 int32 r, secs, nsecs; 420 int64 ns; 421 422 ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32; 423 g->m->scalararg[0] = 0; 424 g->m->scalararg[1] = 0; 425 426 if(ns >= 0) { 427 secs = runtime·timediv(ns, 1000000000, &nsecs); 428 r = runtime·mach_semaphore_timedwait(g->m->waitsema, secs, nsecs); 429 if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) { 430 g->m->scalararg[0] = -1; 431 return; 432 } 433 if(r != 0) 434 macherror(r, "semaphore_wait"); 435 g->m->scalararg[0] = 0; 436 return; 437 } 438 while((r = runtime·mach_semaphore_wait(g->m->waitsema)) != 0) { 439 if(r == KERN_ABORTED) // interrupted 440 continue; 441 macherror(r, "semaphore_wait"); 442 } 443 g->m->scalararg[0] = 0; 444 return; 445 } 446 447 #pragma textflag NOSPLIT 448 int32 449 runtime·semasleep(int64 ns) 450 { 451 int32 r; 452 void (*fn)(void); 453 454 g->m->scalararg[0] = (uint32)ns; 455 g->m->scalararg[1] = (uint32)(ns>>32); 456 fn = semasleep; 457 runtime·onM(&fn); 458 r = g->m->scalararg[0]; 459 g->m->scalararg[0] = 0; 460 return r; 461 } 462 463 static int32 mach_semrelease_errno; 464 465 static void 466 mach_semrelease_fail(void) 467 { 468 macherror(mach_semrelease_errno, "semaphore_signal"); 469 } 470 471 #pragma textflag NOSPLIT 472 void 473 runtime·mach_semrelease(uint32 sem) 474 { 475 int32 r; 476 void (*fn)(void); 477 478 while((r = runtime·mach_semaphore_signal(sem)) != 0) { 479 if(r == KERN_ABORTED) // interrupted 480 continue; 481 482 // mach_semrelease must be completely nosplit, 483 // because it is called from Go code. 484 // If we're going to die, start that process on the m stack 485 // to avoid a Go stack split. 486 // Only do that if we're actually running on the g stack. 487 // We might be on the gsignal stack, and if so, onM will abort. 488 // We use the global variable instead of scalararg because 489 // we might be on the gsignal stack, having interrupted a 490 // normal call to onM. It doesn't quite matter, since the 491 // program is about to die, but better to be clean. 492 mach_semrelease_errno = r; 493 fn = mach_semrelease_fail; 494 if(g == g->m->curg) 495 runtime·onM(&fn); 496 else 497 fn(); 498 } 499 } 500 501 #pragma textflag NOSPLIT 502 void 503 runtime·osyield(void) 504 { 505 runtime·usleep(1); 506 } 507 508 uintptr 509 runtime·memlimit(void) 510 { 511 // NOTE(rsc): Could use getrlimit here, 512 // like on FreeBSD or Linux, but Darwin doesn't enforce 513 // ulimit -v, so it's unclear why we'd try to stay within 514 // the limit. 515 return 0; 516 } 517 518 void 519 runtime·setsig(int32 i, GoSighandler *fn, bool restart) 520 { 521 SigactionT sa; 522 523 runtime·memclr((byte*)&sa, sizeof sa); 524 sa.sa_flags = SA_SIGINFO|SA_ONSTACK; 525 if(restart) 526 sa.sa_flags |= SA_RESTART; 527 sa.sa_mask = ~(uintptr)0; 528 sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler 529 *(uintptr*)sa.__sigaction_u = (uintptr)fn; 530 runtime·sigaction(i, &sa, nil); 531 } 532 533 GoSighandler* 534 runtime·getsig(int32 i) 535 { 536 SigactionT sa; 537 538 runtime·memclr((byte*)&sa, sizeof sa); 539 runtime·sigaction(i, nil, &sa); 540 return *(void**)sa.__sigaction_u; 541 } 542 543 void 544 runtime·signalstack(byte *p, int32 n) 545 { 546 StackT st; 547 548 st.ss_sp = (void*)p; 549 st.ss_size = n; 550 st.ss_flags = 0; 551 if(p == nil) 552 st.ss_flags = SS_DISABLE; 553 runtime·sigaltstack(&st, nil); 554 } 555 556 void 557 runtime·unblocksignals(void) 558 { 559 runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil); 560 } 561 562 #pragma textflag NOSPLIT 563 int8* 564 runtime·signame(int32 sig) 565 { 566 return runtime·sigtab[sig].name; 567 }