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

View as plain text