...

Source file src/runtime/os_darwin.go

Documentation: runtime

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

View as plain text