...
Run Format

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 "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.set_nsec(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  // BSD interface for threading.
    79  func osinit() {
    80  	// pthread_create delayed until end of goenvs so that we
    81  	// can look at the environment first.
    82  
    83  	ncpu = getncpu()
    84  	physPageSize = getPageSize()
    85  }
    86  
    87  const (
    88  	_CTL_HW      = 6
    89  	_HW_NCPU     = 3
    90  	_HW_PAGESIZE = 7
    91  )
    92  
    93  func getncpu() int32 {
    94  	// Use sysctl to fetch hw.ncpu.
    95  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    96  	out := uint32(0)
    97  	nout := unsafe.Sizeof(out)
    98  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    99  	if ret >= 0 && int32(out) > 0 {
   100  		return int32(out)
   101  	}
   102  	return 1
   103  }
   104  
   105  func getPageSize() uintptr {
   106  	// Use sysctl to fetch hw.pagesize.
   107  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   108  	out := uint32(0)
   109  	nout := unsafe.Sizeof(out)
   110  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   111  	if ret >= 0 && int32(out) > 0 {
   112  		return uintptr(out)
   113  	}
   114  	return 0
   115  }
   116  
   117  var urandom_dev = []byte("/dev/urandom\x00")
   118  
   119  //go:nosplit
   120  func getRandomData(r []byte) {
   121  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   122  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   123  	closefd(fd)
   124  	extendRandom(r, int(n))
   125  }
   126  
   127  func goenvs() {
   128  	goenvs_unix()
   129  }
   130  
   131  // May run with m.p==nil, so write barriers are not allowed.
   132  //go:nowritebarrierrec
   133  func newosproc(mp *m) {
   134  	stk := unsafe.Pointer(mp.g0.stack.hi)
   135  	if false {
   136  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   137  	}
   138  
   139  	// Initialize an attribute object.
   140  	var attr pthreadattr
   141  	var err int32
   142  	err = pthread_attr_init(&attr)
   143  	if err != 0 {
   144  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   145  		exit(1)
   146  	}
   147  
   148  	// Set the stack size we want to use.  64KB for now.
   149  	// TODO: just use OS default size?
   150  	const stackSize = 1 << 16
   151  	if pthread_attr_setstacksize(&attr, stackSize) != 0 {
   152  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   153  		exit(1)
   154  	}
   155  	//mSysStatInc(&memstats.stacks_sys, stackSize) //TODO: do this?
   156  
   157  	// Tell the pthread library we won't join with this thread.
   158  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   159  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   160  		exit(1)
   161  	}
   162  
   163  	// Finally, create the thread. It starts at mstart_stub, which does some low-level
   164  	// setup and then calls mstart.
   165  	var oset sigset
   166  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   167  	err = pthread_create(&attr, funcPC(mstart_stub), unsafe.Pointer(mp))
   168  	sigprocmask(_SIG_SETMASK, &oset, nil)
   169  	if err != 0 {
   170  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   171  		exit(1)
   172  	}
   173  }
   174  
   175  // glue code to call mstart from pthread_create.
   176  func mstart_stub()
   177  
   178  // newosproc0 is a version of newosproc that can be called before the runtime
   179  // is initialized.
   180  //
   181  // This function is not safe to use after initialization as it does not pass an M as fnarg.
   182  //
   183  //go:nosplit
   184  func newosproc0(stacksize uintptr, fn uintptr) {
   185  	// Initialize an attribute object.
   186  	var attr pthreadattr
   187  	var err int32
   188  	err = pthread_attr_init(&attr)
   189  	if err != 0 {
   190  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   191  		exit(1)
   192  	}
   193  
   194  	// Set the stack we want to use.
   195  	if pthread_attr_setstacksize(&attr, stacksize) != 0 {
   196  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   197  		exit(1)
   198  	}
   199  	mSysStatInc(&memstats.stacks_sys, stacksize)
   200  
   201  	// Tell the pthread library we won't join with this thread.
   202  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   203  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   204  		exit(1)
   205  	}
   206  
   207  	// Finally, create the thread. It starts at mstart_stub, which does some low-level
   208  	// setup and then calls mstart.
   209  	var oset sigset
   210  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   211  	err = pthread_create(&attr, fn, nil)
   212  	sigprocmask(_SIG_SETMASK, &oset, nil)
   213  	if err != 0 {
   214  		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
   215  		exit(1)
   216  	}
   217  }
   218  
   219  var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
   220  var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
   221  
   222  // Called to do synchronous initialization of Go code built with
   223  // -buildmode=c-archive or -buildmode=c-shared.
   224  // None of the Go runtime is initialized.
   225  //go:nosplit
   226  //go:nowritebarrierrec
   227  func libpreinit() {
   228  	initsig(true)
   229  }
   230  
   231  // Called to initialize a new m (including the bootstrap m).
   232  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   233  func mpreinit(mp *m) {
   234  	mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
   235  	mp.gsignal.m = mp
   236  }
   237  
   238  // Called to initialize a new m (including the bootstrap m).
   239  // Called on the new thread, cannot allocate memory.
   240  func minit() {
   241  	// The alternate signal stack is buggy on arm and arm64.
   242  	// The signal handler handles it directly.
   243  	if GOARCH != "arm" && GOARCH != "arm64" {
   244  		minitSignalStack()
   245  	}
   246  	minitSignalMask()
   247  }
   248  
   249  // Called from dropm to undo the effect of an minit.
   250  //go:nosplit
   251  func unminit() {
   252  	// The alternate signal stack is buggy on arm and arm64.
   253  	// See minit.
   254  	if GOARCH != "arm" && GOARCH != "arm64" {
   255  		unminitSignals()
   256  	}
   257  }
   258  
   259  //go:nosplit
   260  func osyield() {
   261  	usleep(1)
   262  }
   263  
   264  const (
   265  	_NSIG        = 32
   266  	_SI_USER     = 0 /* empirically true, but not what headers say */
   267  	_SIG_BLOCK   = 1
   268  	_SIG_UNBLOCK = 2
   269  	_SIG_SETMASK = 3
   270  	_SS_DISABLE  = 4
   271  )
   272  
   273  //extern SigTabTT runtime·sigtab[];
   274  
   275  type sigset uint32
   276  
   277  var sigset_all = ^sigset(0)
   278  
   279  //go:nosplit
   280  //go:nowritebarrierrec
   281  func setsig(i uint32, fn uintptr) {
   282  	var sa usigactiont
   283  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   284  	sa.sa_mask = ^uint32(0)
   285  	if fn == funcPC(sighandler) {
   286  		if iscgo {
   287  			fn = funcPC(cgoSigtramp)
   288  		} else {
   289  			fn = funcPC(sigtramp)
   290  		}
   291  	}
   292  	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
   293  	sigaction(i, &sa, nil)
   294  }
   295  
   296  // sigtramp is the callback from libc when a signal is received.
   297  // It is called with the C calling convention.
   298  func sigtramp()
   299  func cgoSigtramp()
   300  
   301  //go:nosplit
   302  //go:nowritebarrierrec
   303  func setsigstack(i uint32) {
   304  	var osa usigactiont
   305  	sigaction(i, nil, &osa)
   306  	handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
   307  	if osa.sa_flags&_SA_ONSTACK != 0 {
   308  		return
   309  	}
   310  	var sa usigactiont
   311  	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
   312  	sa.sa_mask = osa.sa_mask
   313  	sa.sa_flags = osa.sa_flags | _SA_ONSTACK
   314  	sigaction(i, &sa, nil)
   315  }
   316  
   317  //go:nosplit
   318  //go:nowritebarrierrec
   319  func getsig(i uint32) uintptr {
   320  	var sa usigactiont
   321  	sigaction(i, nil, &sa)
   322  	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
   323  }
   324  
   325  // setSignaltstackSP sets the ss_sp field of a stackt.
   326  //go:nosplit
   327  func setSignalstackSP(s *stackt, sp uintptr) {
   328  	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
   329  }
   330  
   331  //go:nosplit
   332  //go:nowritebarrierrec
   333  func sigaddset(mask *sigset, i int) {
   334  	*mask |= 1 << (uint32(i) - 1)
   335  }
   336  
   337  func sigdelset(mask *sigset, i int) {
   338  	*mask &^= 1 << (uint32(i) - 1)
   339  }
   340  
   341  //go:linkname executablePath os.executablePath
   342  var executablePath string
   343  
   344  func sysargs(argc int32, argv **byte) {
   345  	// skip over argv, envv and the first string will be the path
   346  	n := argc + 1
   347  	for argv_index(argv, n) != nil {
   348  		n++
   349  	}
   350  	executablePath = gostringnocopy(argv_index(argv, n+1))
   351  
   352  	// strip "executable_path=" prefix if available, it's added after OS X 10.11.
   353  	const prefix = "executable_path="
   354  	if len(executablePath) > len(prefix) && executablePath[:len(prefix)] == prefix {
   355  		executablePath = executablePath[len(prefix):]
   356  	}
   357  }
   358  

View as plain text