github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 ( 8 "internal/abi" 9 "unsafe" 10 ) 11 12 type mOS struct { 13 initialized bool 14 mutex pthreadmutex 15 cond pthreadcond 16 count int 17 } 18 19 func unimplemented(name string) { 20 println(name, "not implemented") 21 *(*int)(unsafe.Pointer(uintptr(1231))) = 1231 22 } 23 24 //go:nosplit 25 func semacreate(mp *m) { 26 if mp.initialized { 27 return 28 } 29 mp.initialized = true 30 if err := pthread_mutex_init(&mp.mutex, nil); err != 0 { 31 throw("pthread_mutex_init") 32 } 33 if err := pthread_cond_init(&mp.cond, nil); err != 0 { 34 throw("pthread_cond_init") 35 } 36 } 37 38 //go:nosplit 39 func semasleep(ns int64) int32 { 40 var start int64 41 if ns >= 0 { 42 start = nanotime() 43 } 44 g := getg() 45 mp := g.m 46 if g == mp.gsignal { 47 // sema sleep/wakeup are implemented with pthreads, which are not async-signal-safe on Darwin. 48 throw("semasleep on Darwin signal stack") 49 } 50 pthread_mutex_lock(&mp.mutex) 51 for { 52 if mp.count > 0 { 53 mp.count-- 54 pthread_mutex_unlock(&mp.mutex) 55 return 0 56 } 57 if ns >= 0 { 58 spent := nanotime() - start 59 if spent >= ns { 60 pthread_mutex_unlock(&mp.mutex) 61 return -1 62 } 63 var t timespec 64 t.setNsec(ns - spent) 65 err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t) 66 if err == _ETIMEDOUT { 67 pthread_mutex_unlock(&mp.mutex) 68 return -1 69 } 70 } else { 71 pthread_cond_wait(&mp.cond, &mp.mutex) 72 } 73 } 74 } 75 76 //go:nosplit 77 func semawakeup(mp *m) { 78 if g := getg(); g == g.m.gsignal { 79 throw("semawakeup on Darwin signal stack") 80 } 81 pthread_mutex_lock(&mp.mutex) 82 mp.count++ 83 if mp.count > 0 { 84 pthread_cond_signal(&mp.cond) 85 } 86 pthread_mutex_unlock(&mp.mutex) 87 } 88 89 // The read and write file descriptors used by the sigNote functions. 90 var sigNoteRead, sigNoteWrite int32 91 92 // sigNoteSetup initializes a single, there-can-only-be-one, async-signal-safe note. 93 // 94 // The current implementation of notes on Darwin is not async-signal-safe, 95 // because the functions pthread_mutex_lock, pthread_cond_signal, and 96 // pthread_mutex_unlock, called by semawakeup, are not async-signal-safe. 97 // There is only one case where we need to wake up a note from a signal 98 // handler: the sigsend function. The signal handler code does not require 99 // all the features of notes: it does not need to do a timed wait. 100 // This is a separate implementation of notes, based on a pipe, that does 101 // not support timed waits but is async-signal-safe. 102 func sigNoteSetup(*note) { 103 if sigNoteRead != 0 || sigNoteWrite != 0 { 104 // Generalizing this would require avoiding the pipe-fork-closeonexec race, which entangles syscall. 105 throw("duplicate sigNoteSetup") 106 } 107 var errno int32 108 sigNoteRead, sigNoteWrite, errno = pipe() 109 if errno != 0 { 110 throw("pipe failed") 111 } 112 closeonexec(sigNoteRead) 113 closeonexec(sigNoteWrite) 114 115 // Make the write end of the pipe non-blocking, so that if the pipe 116 // buffer is somehow full we will not block in the signal handler. 117 // Leave the read end of the pipe blocking so that we will block 118 // in sigNoteSleep. 119 setNonblock(sigNoteWrite) 120 } 121 122 // sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup. 123 func sigNoteWakeup(*note) { 124 var b byte 125 write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1) 126 } 127 128 // sigNoteSleep waits for a note created by sigNoteSetup to be woken. 129 func sigNoteSleep(*note) { 130 for { 131 var b byte 132 entersyscallblock() 133 n := read(sigNoteRead, unsafe.Pointer(&b), 1) 134 exitsyscall() 135 if n != -_EINTR { 136 return 137 } 138 } 139 } 140 141 // BSD interface for threading. 142 func osinit() { 143 // pthread_create delayed until end of goenvs so that we 144 // can look at the environment first. 145 146 ncpu = getncpu() 147 physPageSize = getPageSize() 148 149 osinit_hack() 150 } 151 152 func sysctlbynameInt32(name []byte) (int32, int32) { 153 out := int32(0) 154 nout := unsafe.Sizeof(out) 155 ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 156 return ret, out 157 } 158 159 //go:linkname internal_cpu_getsysctlbyname internal/cpu.getsysctlbyname 160 func internal_cpu_getsysctlbyname(name []byte) (int32, int32) { 161 return sysctlbynameInt32(name) 162 } 163 164 const ( 165 _CTL_HW = 6 166 _HW_NCPU = 3 167 _HW_PAGESIZE = 7 168 ) 169 170 func getncpu() int32 { 171 // Use sysctl to fetch hw.ncpu. 172 mib := [2]uint32{_CTL_HW, _HW_NCPU} 173 out := uint32(0) 174 nout := unsafe.Sizeof(out) 175 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 176 if ret >= 0 && int32(out) > 0 { 177 return int32(out) 178 } 179 return 1 180 } 181 182 func getPageSize() uintptr { 183 // Use sysctl to fetch hw.pagesize. 184 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} 185 out := uint32(0) 186 nout := unsafe.Sizeof(out) 187 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 188 if ret >= 0 && int32(out) > 0 { 189 return uintptr(out) 190 } 191 return 0 192 } 193 194 var urandom_dev = []byte("/dev/urandom\x00") 195 196 //go:nosplit 197 func readRandom(r []byte) int { 198 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 199 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 200 closefd(fd) 201 return int(n) 202 } 203 204 func goenvs() { 205 goenvs_unix() 206 } 207 208 // May run with m.p==nil, so write barriers are not allowed. 209 // 210 //go:nowritebarrierrec 211 func newosproc(mp *m) { 212 stk := unsafe.Pointer(mp.g0.stack.hi) 213 if false { 214 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 215 } 216 217 // Initialize an attribute object. 218 var attr pthreadattr 219 var err int32 220 err = pthread_attr_init(&attr) 221 if err != 0 { 222 writeErrStr(failthreadcreate) 223 exit(1) 224 } 225 226 // Find out OS stack size for our own stack guard. 227 var stacksize uintptr 228 if pthread_attr_getstacksize(&attr, &stacksize) != 0 { 229 writeErrStr(failthreadcreate) 230 exit(1) 231 } 232 mp.g0.stack.hi = stacksize // for mstart 233 234 // Tell the pthread library we won't join with this thread. 235 if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { 236 writeErrStr(failthreadcreate) 237 exit(1) 238 } 239 240 // Finally, create the thread. It starts at mstart_stub, which does some low-level 241 // setup and then calls mstart. 242 var oset sigset 243 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 244 err = retryOnEAGAIN(func() int32 { 245 return pthread_create(&attr, abi.FuncPCABI0(mstart_stub), unsafe.Pointer(mp)) 246 }) 247 sigprocmask(_SIG_SETMASK, &oset, nil) 248 if err != 0 { 249 writeErrStr(failthreadcreate) 250 exit(1) 251 } 252 } 253 254 // glue code to call mstart from pthread_create. 255 func mstart_stub() 256 257 // newosproc0 is a version of newosproc that can be called before the runtime 258 // is initialized. 259 // 260 // This function is not safe to use after initialization as it does not pass an M as fnarg. 261 // 262 //go:nosplit 263 func newosproc0(stacksize uintptr, fn uintptr) { 264 // Initialize an attribute object. 265 var attr pthreadattr 266 var err int32 267 err = pthread_attr_init(&attr) 268 if err != 0 { 269 writeErrStr(failthreadcreate) 270 exit(1) 271 } 272 273 // The caller passes in a suggested stack size, 274 // from when we allocated the stack and thread ourselves, 275 // without libpthread. Now that we're using libpthread, 276 // we use the OS default stack size instead of the suggestion. 277 // Find out that stack size for our own stack guard. 278 if pthread_attr_getstacksize(&attr, &stacksize) != 0 { 279 writeErrStr(failthreadcreate) 280 exit(1) 281 } 282 g0.stack.hi = stacksize // for mstart 283 memstats.stacks_sys.add(int64(stacksize)) 284 285 // Tell the pthread library we won't join with this thread. 286 if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { 287 writeErrStr(failthreadcreate) 288 exit(1) 289 } 290 291 // Finally, create the thread. It starts at mstart_stub, which does some low-level 292 // setup and then calls mstart. 293 var oset sigset 294 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 295 err = pthread_create(&attr, fn, nil) 296 sigprocmask(_SIG_SETMASK, &oset, nil) 297 if err != 0 { 298 writeErrStr(failthreadcreate) 299 exit(1) 300 } 301 } 302 303 // Called to do synchronous initialization of Go code built with 304 // -buildmode=c-archive or -buildmode=c-shared. 305 // None of the Go runtime is initialized. 306 // 307 //go:nosplit 308 //go:nowritebarrierrec 309 func libpreinit() { 310 initsig(true) 311 } 312 313 // Called to initialize a new m (including the bootstrap m). 314 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 315 func mpreinit(mp *m) { 316 mp.gsignal = malg(32 * 1024) // OS X wants >= 8K 317 mp.gsignal.m = mp 318 if GOOS == "darwin" && GOARCH == "arm64" { 319 // mlock the signal stack to work around a kernel bug where it may 320 // SIGILL when the signal stack is not faulted in while a signal 321 // arrives. See issue 42774. 322 mlock(unsafe.Pointer(mp.gsignal.stack.hi-physPageSize), physPageSize) 323 } 324 } 325 326 // Called to initialize a new m (including the bootstrap m). 327 // Called on the new thread, cannot allocate memory. 328 func minit() { 329 // iOS does not support alternate signal stack. 330 // The signal handler handles it directly. 331 if !(GOOS == "ios" && GOARCH == "arm64") { 332 minitSignalStack() 333 } 334 minitSignalMask() 335 getg().m.procid = uint64(pthread_self()) 336 } 337 338 // Called from dropm to undo the effect of an minit. 339 // 340 //go:nosplit 341 func unminit() { 342 // iOS does not support alternate signal stack. 343 // See minit. 344 if !(GOOS == "ios" && GOARCH == "arm64") { 345 unminitSignals() 346 } 347 getg().m.procid = 0 348 } 349 350 // Called from exitm, but not from drop, to undo the effect of thread-owned 351 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. 352 func mdestroy(mp *m) { 353 } 354 355 //go:nosplit 356 func osyield_no_g() { 357 usleep_no_g(1) 358 } 359 360 //go:nosplit 361 func osyield() { 362 usleep(1) 363 } 364 365 const ( 366 _NSIG = 32 367 _SI_USER = 0 /* empirically true, but not what headers say */ 368 _SIG_BLOCK = 1 369 _SIG_UNBLOCK = 2 370 _SIG_SETMASK = 3 371 _SS_DISABLE = 4 372 ) 373 374 //extern SigTabTT runtimeĀ·sigtab[]; 375 376 type sigset uint32 377 378 var sigset_all = ^sigset(0) 379 380 //go:nosplit 381 //go:nowritebarrierrec 382 func setsig(i uint32, fn uintptr) { 383 var sa usigactiont 384 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 385 sa.sa_mask = ^uint32(0) 386 if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go 387 if iscgo { 388 fn = abi.FuncPCABI0(cgoSigtramp) 389 } else { 390 fn = abi.FuncPCABI0(sigtramp) 391 } 392 } 393 *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn 394 sigaction(i, &sa, nil) 395 } 396 397 // sigtramp is the callback from libc when a signal is received. 398 // It is called with the C calling convention. 399 func sigtramp() 400 func cgoSigtramp() 401 402 //go:nosplit 403 //go:nowritebarrierrec 404 func setsigstack(i uint32) { 405 var osa usigactiont 406 sigaction(i, nil, &osa) 407 handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u)) 408 if osa.sa_flags&_SA_ONSTACK != 0 { 409 return 410 } 411 var sa usigactiont 412 *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler 413 sa.sa_mask = osa.sa_mask 414 sa.sa_flags = osa.sa_flags | _SA_ONSTACK 415 sigaction(i, &sa, nil) 416 } 417 418 //go:nosplit 419 //go:nowritebarrierrec 420 func getsig(i uint32) uintptr { 421 var sa usigactiont 422 sigaction(i, nil, &sa) 423 return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) 424 } 425 426 // setSignalstackSP sets the ss_sp field of a stackt. 427 // 428 //go:nosplit 429 func setSignalstackSP(s *stackt, sp uintptr) { 430 *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp 431 } 432 433 //go:nosplit 434 //go:nowritebarrierrec 435 func sigaddset(mask *sigset, i int) { 436 *mask |= 1 << (uint32(i) - 1) 437 } 438 439 func sigdelset(mask *sigset, i int) { 440 *mask &^= 1 << (uint32(i) - 1) 441 } 442 443 func setProcessCPUProfiler(hz int32) { 444 setProcessCPUProfilerTimer(hz) 445 } 446 447 func setThreadCPUProfiler(hz int32) { 448 setThreadCPUProfilerHz(hz) 449 } 450 451 //go:nosplit 452 func validSIGPROF(mp *m, c *sigctxt) bool { 453 return true 454 } 455 456 //go:linkname executablePath os.executablePath 457 var executablePath string 458 459 func sysargs(argc int32, argv **byte) { 460 // skip over argv, envv and the first string will be the path 461 n := argc + 1 462 for argv_index(argv, n) != nil { 463 n++ 464 } 465 executablePath = gostringnocopy(argv_index(argv, n+1)) 466 467 // strip "executable_path=" prefix if available, it's added after OS X 10.11. 468 const prefix = "executable_path=" 469 if len(executablePath) > len(prefix) && executablePath[:len(prefix)] == prefix { 470 executablePath = executablePath[len(prefix):] 471 } 472 } 473 474 func signalM(mp *m, sig int) { 475 pthread_kill(pthread(mp.procid), uint32(sig)) 476 } 477 478 // sigPerThreadSyscall is only used on linux, so we assign a bogus signal 479 // number. 480 const sigPerThreadSyscall = 1 << 31 481 482 //go:nosplit 483 func runPerThreadSyscall() { 484 throw("runPerThreadSyscall only valid on linux") 485 }