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