github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/runtime/os_darwin.go (about)

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