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

View as plain text