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