github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/runtime/os_darwin.go (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 package runtime 6 7 import "unsafe" 8 9 type mOS struct { 10 machport uint32 // return address for mach ipc 11 waitsema uint32 // semaphore for parking on locks 12 } 13 14 func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32 15 func bsdthread_register() int32 16 17 //go:noescape 18 func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 19 20 func mach_reply_port() uint32 21 func mach_task_self() uint32 22 func mach_thread_self() uint32 23 24 //go:noescape 25 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 26 27 func unimplemented(name string) { 28 println(name, "not implemented") 29 *(*int)(unsafe.Pointer(uintptr(1231))) = 1231 30 } 31 32 //go:nosplit 33 func semawakeup(mp *m) { 34 mach_semrelease(mp.waitsema) 35 } 36 37 //go:nosplit 38 func semacreate(mp *m) { 39 if mp.waitsema != 0 { 40 return 41 } 42 systemstack(func() { 43 mp.waitsema = mach_semcreate() 44 }) 45 } 46 47 // BSD interface for threading. 48 func osinit() { 49 // bsdthread_register delayed until end of goenvs so that we 50 // can look at the environment first. 51 52 ncpu = getncpu() 53 } 54 55 func getncpu() int32 { 56 // Use sysctl to fetch hw.ncpu. 57 mib := [2]uint32{6, 3} 58 out := uint32(0) 59 nout := unsafe.Sizeof(out) 60 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 61 if ret >= 0 && int32(out) > 0 { 62 return int32(out) 63 } 64 return 1 65 } 66 67 var urandom_dev = []byte("/dev/urandom\x00") 68 69 //go:nosplit 70 func getRandomData(r []byte) { 71 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 72 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 73 closefd(fd) 74 extendRandom(r, int(n)) 75 } 76 77 func goenvs() { 78 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 !iscgo { 84 if bsdthread_register() != 0 { 85 if gogetenv("DYLD_INSERT_LIBRARIES") != "" { 86 throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)") 87 } 88 throw("runtime: bsdthread_register error") 89 } 90 } 91 } 92 93 // May run with m.p==nil, so write barriers are not allowed. 94 //go:nowritebarrier 95 func newosproc(mp *m, stk unsafe.Pointer) { 96 if false { 97 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 98 } 99 100 var oset sigset 101 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 102 errno := bsdthread_create(stk, unsafe.Pointer(mp), funcPC(mstart)) 103 sigprocmask(_SIG_SETMASK, &oset, nil) 104 105 if errno < 0 { 106 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -errno, ")\n") 107 throw("runtime.newosproc") 108 } 109 } 110 111 // newosproc0 is a version of newosproc that can be called before the runtime 112 // is initialized. 113 // 114 // As Go uses bsdthread_register when running without cgo, this function is 115 // not safe to use after initialization as it does not pass an M as fnarg. 116 // 117 //go:nosplit 118 func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) { 119 stack := sysAlloc(stacksize, &memstats.stacks_sys) 120 if stack == nil { 121 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack))) 122 exit(1) 123 } 124 stk := unsafe.Pointer(uintptr(stack) + stacksize) 125 126 var oset sigset 127 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 128 errno := bsdthread_create(stk, fn, fnarg) 129 sigprocmask(_SIG_SETMASK, &oset, nil) 130 131 if errno < 0 { 132 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 133 exit(1) 134 } 135 } 136 137 var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n") 138 var failthreadcreate = []byte("runtime: failed to create new OS thread\n") 139 140 // Called to do synchronous initialization of Go code built with 141 // -buildmode=c-archive or -buildmode=c-shared. 142 // None of the Go runtime is initialized. 143 //go:nosplit 144 //go:nowritebarrierrec 145 func libpreinit() { 146 initsig(true) 147 } 148 149 // Called to initialize a new m (including the bootstrap m). 150 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 151 func mpreinit(mp *m) { 152 mp.gsignal = malg(32 * 1024) // OS X wants >= 8K 153 mp.gsignal.m = mp 154 } 155 156 //go:nosplit 157 func msigsave(mp *m) { 158 sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) 159 } 160 161 //go:nosplit 162 func msigrestore(sigmask sigset) { 163 sigprocmask(_SIG_SETMASK, &sigmask, nil) 164 } 165 166 //go:nosplit 167 func sigblock() { 168 sigprocmask(_SIG_SETMASK, &sigset_all, nil) 169 } 170 171 // Called to initialize a new m (including the bootstrap m). 172 // Called on the new thread, cannot allocate memory. 173 func minit() { 174 // Initialize signal handling. 175 _g_ := getg() 176 177 // The alternate signal stack is buggy on arm and arm64. 178 // The signal handler handles it directly. 179 // The sigaltstack assembly function does nothing. 180 if GOARCH != "arm" && GOARCH != "arm64" { 181 var st stackt 182 sigaltstack(nil, &st) 183 if st.ss_flags&_SS_DISABLE != 0 { 184 signalstack(&_g_.m.gsignal.stack) 185 _g_.m.newSigstack = true 186 } else { 187 // Use existing signal stack. 188 stsp := uintptr(unsafe.Pointer(st.ss_sp)) 189 _g_.m.gsignal.stack.lo = stsp 190 _g_.m.gsignal.stack.hi = stsp + st.ss_size 191 _g_.m.gsignal.stackguard0 = stsp + _StackGuard 192 _g_.m.gsignal.stackguard1 = stsp + _StackGuard 193 _g_.m.gsignal.stackAlloc = st.ss_size 194 _g_.m.newSigstack = false 195 } 196 } 197 198 // restore signal mask from m.sigmask and unblock essential signals 199 nmask := _g_.m.sigmask 200 for i := range sigtable { 201 if sigtable[i].flags&_SigUnblock != 0 { 202 nmask &^= 1 << (uint32(i) - 1) 203 } 204 } 205 sigprocmask(_SIG_SETMASK, &nmask, nil) 206 } 207 208 // Called from dropm to undo the effect of an minit. 209 //go:nosplit 210 func unminit() { 211 if getg().m.newSigstack { 212 signalstack(nil) 213 } 214 } 215 216 // Mach IPC, to get at semaphores 217 // Definitions are in /usr/include/mach on a Mac. 218 219 func macherror(r int32, fn string) { 220 print("mach error ", fn, ": ", r, "\n") 221 throw("mach error") 222 } 223 224 const _DebugMach = false 225 226 var zerondr machndr 227 228 func mach_msgh_bits(a, b uint32) uint32 { 229 return a | b<<8 230 } 231 232 func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 { 233 // TODO: Loop on interrupt. 234 return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify) 235 } 236 237 // Mach RPC (MIG) 238 const ( 239 _MinMachMsg = 48 240 _MachReply = 100 241 ) 242 243 type codemsg struct { 244 h machheader 245 ndr machndr 246 code int32 247 } 248 249 func machcall(h *machheader, maxsize int32, rxsize int32) int32 { 250 _g_ := getg() 251 port := _g_.m.machport 252 if port == 0 { 253 port = mach_reply_port() 254 _g_.m.machport = port 255 } 256 257 h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE) 258 h.msgh_local_port = port 259 h.msgh_reserved = 0 260 id := h.msgh_id 261 262 if _DebugMach { 263 p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h)) 264 print("send:\t") 265 var i uint32 266 for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ { 267 print(" ", p[i]) 268 if i%8 == 7 { 269 print("\n\t") 270 } 271 } 272 if i%8 != 0 { 273 print("\n") 274 } 275 } 276 ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0) 277 if ret != 0 { 278 if _DebugMach { 279 print("mach_msg error ", ret, "\n") 280 } 281 return ret 282 } 283 if _DebugMach { 284 p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h)) 285 var i uint32 286 for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ { 287 print(" ", p[i]) 288 if i%8 == 7 { 289 print("\n\t") 290 } 291 } 292 if i%8 != 0 { 293 print("\n") 294 } 295 } 296 if h.msgh_id != id+_MachReply { 297 if _DebugMach { 298 print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n") 299 } 300 return -303 // MIG_REPLY_MISMATCH 301 } 302 // Look for a response giving the return value. 303 // Any call can send this back with an error, 304 // and some calls only have return values so they 305 // send it back on success too. I don't quite see how 306 // you know it's one of these and not the full response 307 // format, so just look if the message is right. 308 c := (*codemsg)(unsafe.Pointer(h)) 309 if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 { 310 if _DebugMach { 311 print("mig result ", c.code, "\n") 312 } 313 return c.code 314 } 315 if h.msgh_size != uint32(rxsize) { 316 if _DebugMach { 317 print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n") 318 } 319 return -307 // MIG_ARRAY_TOO_LARGE 320 } 321 return 0 322 } 323 324 // Semaphores! 325 326 const ( 327 tmach_semcreate = 3418 328 rmach_semcreate = tmach_semcreate + _MachReply 329 330 tmach_semdestroy = 3419 331 rmach_semdestroy = tmach_semdestroy + _MachReply 332 333 _KERN_ABORTED = 14 334 _KERN_OPERATION_TIMED_OUT = 49 335 ) 336 337 type tmach_semcreatemsg struct { 338 h machheader 339 ndr machndr 340 policy int32 341 value int32 342 } 343 344 type rmach_semcreatemsg struct { 345 h machheader 346 body machbody 347 semaphore machport 348 } 349 350 type tmach_semdestroymsg struct { 351 h machheader 352 body machbody 353 semaphore machport 354 } 355 356 func mach_semcreate() uint32 { 357 var m [256]uint8 358 tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m)) 359 rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m)) 360 361 tx.h.msgh_bits = 0 362 tx.h.msgh_size = uint32(unsafe.Sizeof(*tx)) 363 tx.h.msgh_remote_port = mach_task_self() 364 tx.h.msgh_id = tmach_semcreate 365 tx.ndr = zerondr 366 367 tx.policy = 0 // 0 = SYNC_POLICY_FIFO 368 tx.value = 0 369 370 for { 371 r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx))) 372 if r == 0 { 373 break 374 } 375 if r == _KERN_ABORTED { // interrupted 376 continue 377 } 378 macherror(r, "semaphore_create") 379 } 380 if rx.body.msgh_descriptor_count != 1 { 381 unimplemented("mach_semcreate desc count") 382 } 383 return rx.semaphore.name 384 } 385 386 func mach_semdestroy(sem uint32) { 387 var m [256]uint8 388 tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m)) 389 390 tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX 391 tx.h.msgh_size = uint32(unsafe.Sizeof(*tx)) 392 tx.h.msgh_remote_port = mach_task_self() 393 tx.h.msgh_id = tmach_semdestroy 394 tx.body.msgh_descriptor_count = 1 395 tx.semaphore.name = sem 396 tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND 397 tx.semaphore._type = 0 398 399 for { 400 r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0) 401 if r == 0 { 402 break 403 } 404 if r == _KERN_ABORTED { // interrupted 405 continue 406 } 407 macherror(r, "semaphore_destroy") 408 } 409 } 410 411 // The other calls have simple system call traps in sys_darwin_{amd64,386}.s 412 413 func mach_semaphore_wait(sema uint32) int32 414 func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 415 func mach_semaphore_signal(sema uint32) int32 416 func mach_semaphore_signal_all(sema uint32) int32 417 418 func semasleep1(ns int64) int32 { 419 _g_ := getg() 420 421 if ns >= 0 { 422 var nsecs int32 423 secs := timediv(ns, 1000000000, &nsecs) 424 r := mach_semaphore_timedwait(_g_.m.waitsema, uint32(secs), uint32(nsecs)) 425 if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT { 426 return -1 427 } 428 if r != 0 { 429 macherror(r, "semaphore_wait") 430 } 431 return 0 432 } 433 434 for { 435 r := mach_semaphore_wait(_g_.m.waitsema) 436 if r == 0 { 437 break 438 } 439 if r == _KERN_ABORTED { // interrupted 440 continue 441 } 442 macherror(r, "semaphore_wait") 443 } 444 return 0 445 } 446 447 //go:nosplit 448 func semasleep(ns int64) int32 { 449 var r int32 450 systemstack(func() { 451 r = semasleep1(ns) 452 }) 453 return r 454 } 455 456 //go:nosplit 457 func mach_semrelease(sem uint32) { 458 for { 459 r := mach_semaphore_signal(sem) 460 if r == 0 { 461 break 462 } 463 if r == _KERN_ABORTED { // interrupted 464 continue 465 } 466 467 // mach_semrelease must be completely nosplit, 468 // because it is called from Go code. 469 // If we're going to die, start that process on the system stack 470 // to avoid a Go stack split. 471 systemstack(func() { macherror(r, "semaphore_signal") }) 472 } 473 } 474 475 //go:nosplit 476 func osyield() { 477 usleep(1) 478 } 479 480 func memlimit() uintptr { 481 // NOTE(rsc): Could use getrlimit here, 482 // like on FreeBSD or Linux, but Darwin doesn't enforce 483 // ulimit -v, so it's unclear why we'd try to stay within 484 // the limit. 485 return 0 486 } 487 488 const ( 489 _NSIG = 32 490 _SI_USER = 0 /* empirically true, but not what headers say */ 491 _SIG_BLOCK = 1 492 _SIG_UNBLOCK = 2 493 _SIG_SETMASK = 3 494 _SS_DISABLE = 4 495 ) 496 497 //go:noescape 498 func sigprocmask(how uint32, new, old *sigset) 499 500 //go:noescape 501 func sigaction(mode uint32, new *sigactiont, old *usigactiont) 502 503 //go:noescape 504 func sigaltstack(new, old *stackt) 505 506 // darwin/arm64 uses registers instead of stack-based arguments. 507 // TODO: does this matter? 508 func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) 509 510 //go:noescape 511 func setitimer(mode int32, new, old *itimerval) 512 513 func raise(sig int32) 514 func raiseproc(sig int32) 515 516 //extern SigTabTT runtimeĀ·sigtab[]; 517 518 type sigset uint32 519 520 var sigset_all = ^sigset(0) 521 522 //go:nosplit 523 //go:nowritebarrierrec 524 func setsig(i int32, fn uintptr, restart bool) { 525 var sa sigactiont 526 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 527 if restart { 528 sa.sa_flags |= _SA_RESTART 529 } 530 sa.sa_mask = ^uint32(0) 531 sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtimeĀ·sigtramp's job is to call into real handler 532 *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn 533 sigaction(uint32(i), &sa, nil) 534 } 535 536 //go:nosplit 537 //go:nowritebarrierrec 538 func setsigstack(i int32) { 539 var osa usigactiont 540 sigaction(uint32(i), nil, &osa) 541 handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u)) 542 if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || osa.sa_flags&_SA_ONSTACK != 0 { 543 return 544 } 545 var sa sigactiont 546 *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler 547 sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) 548 sa.sa_mask = osa.sa_mask 549 sa.sa_flags = osa.sa_flags | _SA_ONSTACK 550 sigaction(uint32(i), &sa, nil) 551 } 552 553 //go:nosplit 554 //go:nowritebarrierrec 555 func getsig(i int32) uintptr { 556 var sa usigactiont 557 sigaction(uint32(i), nil, &sa) 558 return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) 559 } 560 561 //go:nosplit 562 func signalstack(s *stack) { 563 var st stackt 564 if s == nil { 565 st.ss_flags = _SS_DISABLE 566 } else { 567 st.ss_sp = (*byte)(unsafe.Pointer(s.lo)) 568 st.ss_size = s.hi - s.lo 569 st.ss_flags = 0 570 } 571 sigaltstack(&st, nil) 572 } 573 574 //go:nosplit 575 //go:nowritebarrierrec 576 func updatesigmask(m sigmask) { 577 s := sigset(m[0]) 578 sigprocmask(_SIG_SETMASK, &s, nil) 579 } 580 581 func unblocksig(sig int32) { 582 mask := sigset(1) << (uint32(sig) - 1) 583 sigprocmask(_SIG_UNBLOCK, &mask, nil) 584 }