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