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