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  	initWorkingDir()
   152  }
   153  
   154  func sysctlbynameInt32(name []byte) (int32, int32) {
   155  	out := int32(0)
   156  	nout := unsafe.Sizeof(out)
   157  	ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   158  	return ret, out
   159  }
   160  
   161  func sysctlbynameBytes(name, out []byte) int32 {
   162  	nout := uintptr(len(out))
   163  	ret := sysctlbyname(&name[0], &out[0], &nout, nil, 0)
   164  	return ret
   165  }
   166  
   167  //go:linkname internal_cpu_sysctlbynameInt32 internal/cpu.sysctlbynameInt32
   168  func internal_cpu_sysctlbynameInt32(name []byte) (int32, int32) {
   169  	return sysctlbynameInt32(name)
   170  }
   171  
   172  //go:linkname internal_cpu_sysctlbynameBytes internal/cpu.sysctlbynameBytes
   173  func internal_cpu_sysctlbynameBytes(name, out []byte) int32 {
   174  	return sysctlbynameBytes(name, out)
   175  }
   176  
   177  const (
   178  	_CTL_HW      = 6
   179  	_HW_NCPU     = 3
   180  	_HW_PAGESIZE = 7
   181  )
   182  
   183  func getCPUCount() int32 {
   184  	// Use sysctl to fetch hw.ncpu.
   185  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
   186  	out := uint32(0)
   187  	nout := unsafe.Sizeof(out)
   188  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   189  	if ret >= 0 && int32(out) > 0 {
   190  		return int32(out)
   191  	}
   192  	return 1
   193  }
   194  
   195  func getPageSize() uintptr {
   196  	// Use sysctl to fetch hw.pagesize.
   197  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   198  	out := uint32(0)
   199  	nout := unsafe.Sizeof(out)
   200  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   201  	if ret >= 0 && int32(out) > 0 {
   202  		return uintptr(out)
   203  	}
   204  	return 0
   205  }
   206  
   207  //go:nosplit
   208  func readRandom(r []byte) int {
   209  	arc4random_buf(unsafe.Pointer(&r[0]), int32(len(r)))
   210  	return len(r)
   211  }
   212  
   213  func goenvs() {
   214  	goenvs_unix()
   215  }
   216  
   217  // May run with m.p==nil, so write barriers are not allowed.
   218  //
   219  //go:nowritebarrierrec
   220  func newosproc(mp *m) {
   221  	stk := unsafe.Pointer(mp.g0.stack.hi)
   222  	if false {
   223  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   224  	}
   225  
   226  	// Initialize an attribute object.
   227  	var attr pthreadattr
   228  	var err int32
   229  	err = pthread_attr_init(&attr)
   230  	if err != 0 {
   231  		writeErrStr(failthreadcreate)
   232  		exit(1)
   233  	}
   234  
   235  	// Find out OS stack size for our own stack guard.
   236  	var stacksize uintptr
   237  	if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
   238  		writeErrStr(failthreadcreate)
   239  		exit(1)
   240  	}
   241  	mp.g0.stack.hi = stacksize // for mstart
   242  
   243  	// Tell the pthread library we won't join with this thread.
   244  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   245  		writeErrStr(failthreadcreate)
   246  		exit(1)
   247  	}
   248  
   249  	// Finally, create the thread. It starts at mstart_stub, which does some low-level
   250  	// setup and then calls mstart.
   251  	var oset sigset
   252  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   253  	err = retryOnEAGAIN(func() int32 {
   254  		return pthread_create(&attr, abi.FuncPCABI0(mstart_stub), unsafe.Pointer(mp))
   255  	})
   256  	sigprocmask(_SIG_SETMASK, &oset, nil)
   257  	if err != 0 {
   258  		writeErrStr(failthreadcreate)
   259  		exit(1)
   260  	}
   261  }
   262  
   263  // glue code to call mstart from pthread_create.
   264  func mstart_stub()
   265  
   266  // newosproc0 is a version of newosproc that can be called before the runtime
   267  // is initialized.
   268  //
   269  // This function is not safe to use after initialization as it does not pass an M as fnarg.
   270  //
   271  //go:nosplit
   272  func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
   273  	// Initialize an attribute object.
   274  	var attr pthreadattr
   275  	var err int32
   276  	err = pthread_attr_init(&attr)
   277  	if err != 0 {
   278  		writeErrStr(failthreadcreate)
   279  		exit(1)
   280  	}
   281  
   282  	// The caller passes in a suggested stack size,
   283  	// from when we allocated the stack and thread ourselves,
   284  	// without libpthread. Now that we're using libpthread,
   285  	// we use the OS default stack size instead of the suggestion.
   286  	// Find out that stack size for our own stack guard.
   287  	if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
   288  		writeErrStr(failthreadcreate)
   289  		exit(1)
   290  	}
   291  	g0.stack.hi = stacksize // for mstart
   292  	memstats.stacks_sys.add(int64(stacksize))
   293  
   294  	// Tell the pthread library we won't join with this thread.
   295  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   296  		writeErrStr(failthreadcreate)
   297  		exit(1)
   298  	}
   299  
   300  	// Finally, create the thread. It starts at mstart_stub, which does some low-level
   301  	// setup and then calls mstart.
   302  	var oset sigset
   303  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   304  	err = pthread_create(&attr, uintptr(fn), nil)
   305  	sigprocmask(_SIG_SETMASK, &oset, nil)
   306  	if err != 0 {
   307  		writeErrStr(failthreadcreate)
   308  		exit(1)
   309  	}
   310  }
   311  
   312  // Called to do synchronous initialization of Go code built with
   313  // -buildmode=c-archive or -buildmode=c-shared.
   314  // None of the Go runtime is initialized.
   315  //
   316  //go:nosplit
   317  //go:nowritebarrierrec
   318  func libpreinit() {
   319  	initsig(true)
   320  }
   321  
   322  // Called to initialize a new m (including the bootstrap m).
   323  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   324  func mpreinit(mp *m) {
   325  	mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
   326  	mp.gsignal.m = mp
   327  	if GOOS == "darwin" && GOARCH == "arm64" {
   328  		// mlock the signal stack to work around a kernel bug where it may
   329  		// SIGILL when the signal stack is not faulted in while a signal
   330  		// arrives. See issue 42774.
   331  		mlock(unsafe.Pointer(mp.gsignal.stack.hi-physPageSize), physPageSize)
   332  	}
   333  }
   334  
   335  // Called to initialize a new m (including the bootstrap m).
   336  // Called on the new thread, cannot allocate memory.
   337  func minit() {
   338  	// iOS does not support alternate signal stack.
   339  	// The signal handler handles it directly.
   340  	if !(GOOS == "ios" && GOARCH == "arm64") {
   341  		minitSignalStack()
   342  	}
   343  	minitSignalMask()
   344  	getg().m.procid = uint64(pthread_self())
   345  }
   346  
   347  // Called from dropm to undo the effect of an minit.
   348  //
   349  //go:nosplit
   350  func unminit() {
   351  	// iOS does not support alternate signal stack.
   352  	// See minit.
   353  	if !(GOOS == "ios" && GOARCH == "arm64") {
   354  		unminitSignals()
   355  	}
   356  	getg().m.procid = 0
   357  }
   358  
   359  // Called from mexit, but not from dropm, to undo the effect of thread-owned
   360  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   361  //
   362  // This always runs without a P, so //go:nowritebarrierrec is required.
   363  //
   364  //go:nowritebarrierrec
   365  func mdestroy(mp *m) {
   366  }
   367  
   368  //go:nosplit
   369  func osyield_no_g() {
   370  	usleep_no_g(1)
   371  }
   372  
   373  //go:nosplit
   374  func osyield() {
   375  	usleep(1)
   376  }
   377  
   378  const (
   379  	_NSIG        = 32
   380  	_SI_USER     = 0 /* empirically true, but not what headers say */
   381  	_SIG_BLOCK   = 1
   382  	_SIG_UNBLOCK = 2
   383  	_SIG_SETMASK = 3
   384  	_SS_DISABLE  = 4
   385  )
   386  
   387  //extern SigTabTT runtimeĀ·sigtab[];
   388  
   389  type sigset uint32
   390  
   391  var sigset_all = ^sigset(0)
   392  
   393  //go:nosplit
   394  //go:nowritebarrierrec
   395  func setsig(i uint32, fn uintptr) {
   396  	var sa usigactiont
   397  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   398  	sa.sa_mask = ^uint32(0)
   399  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   400  		if iscgo {
   401  			fn = abi.FuncPCABI0(cgoSigtramp)
   402  		} else {
   403  			fn = abi.FuncPCABI0(sigtramp)
   404  		}
   405  	}
   406  	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
   407  	sigaction(i, &sa, nil)
   408  }
   409  
   410  // sigtramp is the callback from libc when a signal is received.
   411  // It is called with the C calling convention.
   412  func sigtramp()
   413  func cgoSigtramp()
   414  
   415  //go:nosplit
   416  //go:nowritebarrierrec
   417  func setsigstack(i uint32) {
   418  	var osa usigactiont
   419  	sigaction(i, nil, &osa)
   420  	handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
   421  	if osa.sa_flags&_SA_ONSTACK != 0 {
   422  		return
   423  	}
   424  	var sa usigactiont
   425  	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
   426  	sa.sa_mask = osa.sa_mask
   427  	sa.sa_flags = osa.sa_flags | _SA_ONSTACK
   428  	sigaction(i, &sa, nil)
   429  }
   430  
   431  //go:nosplit
   432  //go:nowritebarrierrec
   433  func getsig(i uint32) uintptr {
   434  	var sa usigactiont
   435  	sigaction(i, nil, &sa)
   436  	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
   437  }
   438  
   439  // setSignalstackSP sets the ss_sp field of a stackt.
   440  //
   441  //go:nosplit
   442  func setSignalstackSP(s *stackt, sp uintptr) {
   443  	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   444  }
   445  
   446  //go:nosplit
   447  //go:nowritebarrierrec
   448  func sigaddset(mask *sigset, i int) {
   449  	*mask |= 1 << (uint32(i) - 1)
   450  }
   451  
   452  func sigdelset(mask *sigset, i int) {
   453  	*mask &^= 1 << (uint32(i) - 1)
   454  }
   455  
   456  func setProcessCPUProfiler(hz int32) {
   457  	setProcessCPUProfilerTimer(hz)
   458  }
   459  
   460  func setThreadCPUProfiler(hz int32) {
   461  	setThreadCPUProfilerHz(hz)
   462  }
   463  
   464  //go:nosplit
   465  func validSIGPROF(mp *m, c *sigctxt) bool {
   466  	return true
   467  }
   468  
   469  //go:linkname executablePath os.executablePath
   470  var executablePath string
   471  
   472  func sysargs(argc int32, argv **byte) {
   473  	// skip over argv, envv and the first string will be the path
   474  	n := argc + 1
   475  	for argv_index(argv, n) != nil {
   476  		n++
   477  	}
   478  	executablePath = gostringnocopy(argv_index(argv, n+1))
   479  
   480  	// strip "executable_path=" prefix if available, it's added after OS X 10.11.
   481  	executablePath = stringslite.TrimPrefix(executablePath, "executable_path=")
   482  }
   483  
   484  func signalM(mp *m, sig int) {
   485  	pthread_kill(pthread(mp.procid), uint32(sig))
   486  }
   487  
   488  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   489  // number.
   490  const sigPerThreadSyscall = 1 << 31
   491  
   492  //go:nosplit
   493  func runPerThreadSyscall() {
   494  	throw("runPerThreadSyscall only valid on linux")
   495  }
   496  

View as plain text