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

View as plain text