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