Source file src/runtime/os_darwin.go

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

View as plain text