...

Source file src/runtime/os_netbsd.go

Documentation: runtime

     1  // Copyright 2014 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/goarch"
    10  	"internal/runtime/atomic"
    11  	"unsafe"
    12  )
    13  
    14  const (
    15  	_SS_DISABLE  = 4
    16  	_SIG_BLOCK   = 1
    17  	_SIG_UNBLOCK = 2
    18  	_SIG_SETMASK = 3
    19  	_NSIG        = 33
    20  	_SI_USER     = 0
    21  
    22  	// From NetBSD's <sys/ucontext.h>
    23  	_UC_SIGMASK = 0x01
    24  	_UC_CPU     = 0x04
    25  
    26  	// From <sys/lwp.h>
    27  	_LWP_DETACHED = 0x00000040
    28  )
    29  
    30  type mOS struct {
    31  	waitsemacount uint32
    32  }
    33  
    34  //go:noescape
    35  func setitimer(mode int32, new, old *itimerval)
    36  
    37  //go:noescape
    38  func sigaction(sig uint32, new, old *sigactiont)
    39  
    40  //go:noescape
    41  func sigaltstack(new, old *stackt)
    42  
    43  //go:noescape
    44  func sigprocmask(how int32, new, old *sigset)
    45  
    46  //go:noescape
    47  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    48  
    49  func lwp_tramp()
    50  
    51  func raiseproc(sig uint32)
    52  
    53  func lwp_kill(tid int32, sig int)
    54  
    55  //go:noescape
    56  func getcontext(ctxt unsafe.Pointer)
    57  
    58  //go:noescape
    59  func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
    60  
    61  //go:noescape
    62  func lwp_park(clockid, flags int32, ts *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
    63  
    64  //go:noescape
    65  func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
    66  
    67  func lwp_self() int32
    68  
    69  func osyield()
    70  
    71  //go:nosplit
    72  func osyield_no_g() {
    73  	osyield()
    74  }
    75  
    76  func kqueue() int32
    77  
    78  //go:noescape
    79  func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    80  
    81  func pipe2(flags int32) (r, w int32, errno int32)
    82  func fcntl(fd, cmd, arg int32) (ret int32, errno int32)
    83  
    84  func issetugid() int32
    85  
    86  const (
    87  	_ESRCH     = 3
    88  	_ETIMEDOUT = 60
    89  
    90  	// From NetBSD's <sys/time.h>
    91  	_CLOCK_REALTIME  = 0
    92  	_CLOCK_VIRTUAL   = 1
    93  	_CLOCK_PROF      = 2
    94  	_CLOCK_MONOTONIC = 3
    95  
    96  	_TIMER_RELTIME = 0
    97  	_TIMER_ABSTIME = 1
    98  )
    99  
   100  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
   101  
   102  // From NetBSD's <sys/sysctl.h>
   103  const (
   104  	_CTL_KERN   = 1
   105  	_KERN_OSREV = 3
   106  
   107  	_CTL_HW        = 6
   108  	_HW_NCPU       = 3
   109  	_HW_PAGESIZE   = 7
   110  	_HW_NCPUONLINE = 16
   111  )
   112  
   113  func sysctlInt(mib []uint32) (int32, bool) {
   114  	var out int32
   115  	nout := unsafe.Sizeof(out)
   116  	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   117  	if ret < 0 {
   118  		return 0, false
   119  	}
   120  	return out, true
   121  }
   122  
   123  func getncpu() int32 {
   124  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok {
   125  		return int32(n)
   126  	}
   127  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok {
   128  		return int32(n)
   129  	}
   130  	return 1
   131  }
   132  
   133  func getPageSize() uintptr {
   134  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   135  	out := uint32(0)
   136  	nout := unsafe.Sizeof(out)
   137  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   138  	if ret >= 0 {
   139  		return uintptr(out)
   140  	}
   141  	return 0
   142  }
   143  
   144  func getOSRev() int {
   145  	if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok {
   146  		return int(osrev)
   147  	}
   148  	return 0
   149  }
   150  
   151  //go:nosplit
   152  func semacreate(mp *m) {
   153  }
   154  
   155  //go:nosplit
   156  func semasleep(ns int64) int32 {
   157  	gp := getg()
   158  	var deadline int64
   159  	if ns >= 0 {
   160  		deadline = nanotime() + ns
   161  	}
   162  
   163  	for {
   164  		v := atomic.Load(&gp.m.waitsemacount)
   165  		if v > 0 {
   166  			if atomic.Cas(&gp.m.waitsemacount, v, v-1) {
   167  				return 0 // semaphore acquired
   168  			}
   169  			continue
   170  		}
   171  
   172  		// Sleep until unparked by semawakeup or timeout.
   173  		var tsp *timespec
   174  		var ts timespec
   175  		if ns >= 0 {
   176  			wait := deadline - nanotime()
   177  			if wait <= 0 {
   178  				return -1
   179  			}
   180  			ts.setNsec(wait)
   181  			tsp = &ts
   182  		}
   183  		ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&gp.m.waitsemacount), nil)
   184  		if ret == _ETIMEDOUT {
   185  			return -1
   186  		}
   187  	}
   188  }
   189  
   190  //go:nosplit
   191  func semawakeup(mp *m) {
   192  	atomic.Xadd(&mp.waitsemacount, 1)
   193  	// From NetBSD's _lwp_unpark(2) manual:
   194  	// "If the target LWP is not currently waiting, it will return
   195  	// immediately upon the next call to _lwp_park()."
   196  	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
   197  	if ret != 0 && ret != _ESRCH {
   198  		// semawakeup can be called on signal stack.
   199  		systemstack(func() {
   200  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   201  		})
   202  	}
   203  }
   204  
   205  // May run with m.p==nil, so write barriers are not allowed.
   206  //
   207  //go:nowritebarrier
   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  	var uc ucontextt
   215  	getcontext(unsafe.Pointer(&uc))
   216  
   217  	// _UC_SIGMASK does not seem to work here.
   218  	// It would be nice if _UC_SIGMASK and _UC_STACK
   219  	// worked so that we could do all the work setting
   220  	// the sigmask and the stack here, instead of setting
   221  	// the mask here and the stack in netbsdMstart.
   222  	// For now do the blocking manually.
   223  	uc.uc_flags = _UC_SIGMASK | _UC_CPU
   224  	uc.uc_link = nil
   225  	uc.uc_sigmask = sigset_all
   226  
   227  	var oset sigset
   228  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   229  
   230  	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, abi.FuncPCABI0(netbsdMstart))
   231  
   232  	ret := retryOnEAGAIN(func() int32 {
   233  		errno := lwp_create(unsafe.Pointer(&uc), _LWP_DETACHED, unsafe.Pointer(&mp.procid))
   234  		// lwp_create returns negative errno
   235  		return -errno
   236  	})
   237  	sigprocmask(_SIG_SETMASK, &oset, nil)
   238  	if ret != 0 {
   239  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", ret, ")\n")
   240  		if ret == _EAGAIN {
   241  			println("runtime: may need to increase max user processes (ulimit -p)")
   242  		}
   243  		throw("runtime.newosproc")
   244  	}
   245  }
   246  
   247  // mstart is the entry-point for new Ms.
   248  // It is written in assembly, uses ABI0, is marked TOPFRAME, and calls netbsdMstart0.
   249  func netbsdMstart()
   250  
   251  // netbsdMstart0 is the function call that starts executing a newly
   252  // created thread. On NetBSD, a new thread inherits the signal stack
   253  // of the creating thread. That confuses minit, so we remove that
   254  // signal stack here before calling the regular mstart. It's a bit
   255  // baroque to remove a signal stack here only to add one in minit, but
   256  // it's a simple change that keeps NetBSD working like other OS's.
   257  // At this point all signals are blocked, so there is no race.
   258  //
   259  //go:nosplit
   260  func netbsdMstart0() {
   261  	st := stackt{ss_flags: _SS_DISABLE}
   262  	sigaltstack(&st, nil)
   263  	mstart0()
   264  }
   265  
   266  func osinit() {
   267  	ncpu = getncpu()
   268  	if physPageSize == 0 {
   269  		physPageSize = getPageSize()
   270  	}
   271  	needSysmonWorkaround = getOSRev() < 902000000 // NetBSD 9.2
   272  }
   273  
   274  var urandom_dev = []byte("/dev/urandom\x00")
   275  
   276  //go:nosplit
   277  func readRandom(r []byte) int {
   278  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   279  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   280  	closefd(fd)
   281  	return int(n)
   282  }
   283  
   284  func goenvs() {
   285  	goenvs_unix()
   286  }
   287  
   288  // Called to initialize a new m (including the bootstrap m).
   289  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   290  func mpreinit(mp *m) {
   291  	mp.gsignal = malg(32 * 1024)
   292  	mp.gsignal.m = mp
   293  }
   294  
   295  // Called to initialize a new m (including the bootstrap m).
   296  // Called on the new thread, cannot allocate memory.
   297  func minit() {
   298  	gp := getg()
   299  	gp.m.procid = uint64(lwp_self())
   300  
   301  	// On NetBSD a thread created by pthread_create inherits the
   302  	// signal stack of the creating thread. We always create a
   303  	// new signal stack here, to avoid having two Go threads using
   304  	// the same signal stack. This breaks the case of a thread
   305  	// created in C that calls sigaltstack and then calls a Go
   306  	// function, because we will lose track of the C code's
   307  	// sigaltstack, but it's the best we can do.
   308  	signalstack(&gp.m.gsignal.stack)
   309  	gp.m.newSigstack = true
   310  
   311  	minitSignalMask()
   312  }
   313  
   314  // Called from dropm to undo the effect of an minit.
   315  //
   316  //go:nosplit
   317  func unminit() {
   318  	unminitSignals()
   319  	// Don't clear procid, it is used by locking (semawake), and locking
   320  	// must continue working after unminit.
   321  }
   322  
   323  // Called from exitm, but not from drop, to undo the effect of thread-owned
   324  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   325  func mdestroy(mp *m) {
   326  }
   327  
   328  func sigtramp()
   329  
   330  type sigactiont struct {
   331  	sa_sigaction uintptr
   332  	sa_mask      sigset
   333  	sa_flags     int32
   334  }
   335  
   336  //go:nosplit
   337  //go:nowritebarrierrec
   338  func setsig(i uint32, fn uintptr) {
   339  	var sa sigactiont
   340  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   341  	sa.sa_mask = sigset_all
   342  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   343  		fn = abi.FuncPCABI0(sigtramp)
   344  	}
   345  	sa.sa_sigaction = fn
   346  	sigaction(i, &sa, nil)
   347  }
   348  
   349  //go:nosplit
   350  //go:nowritebarrierrec
   351  func setsigstack(i uint32) {
   352  	throw("setsigstack")
   353  }
   354  
   355  //go:nosplit
   356  //go:nowritebarrierrec
   357  func getsig(i uint32) uintptr {
   358  	var sa sigactiont
   359  	sigaction(i, nil, &sa)
   360  	return sa.sa_sigaction
   361  }
   362  
   363  // setSignalstackSP sets the ss_sp field of a stackt.
   364  //
   365  //go:nosplit
   366  func setSignalstackSP(s *stackt, sp uintptr) {
   367  	s.ss_sp = sp
   368  }
   369  
   370  //go:nosplit
   371  //go:nowritebarrierrec
   372  func sigaddset(mask *sigset, i int) {
   373  	mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
   374  }
   375  
   376  func sigdelset(mask *sigset, i int) {
   377  	mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   378  }
   379  
   380  //go:nosplit
   381  func (c *sigctxt) fixsigcode(sig uint32) {
   382  }
   383  
   384  func setProcessCPUProfiler(hz int32) {
   385  	setProcessCPUProfilerTimer(hz)
   386  }
   387  
   388  func setThreadCPUProfiler(hz int32) {
   389  	setThreadCPUProfilerHz(hz)
   390  }
   391  
   392  //go:nosplit
   393  func validSIGPROF(mp *m, c *sigctxt) bool {
   394  	return true
   395  }
   396  
   397  func sysargs(argc int32, argv **byte) {
   398  	n := argc + 1
   399  
   400  	// skip over argv, envp to get to auxv
   401  	for argv_index(argv, n) != nil {
   402  		n++
   403  	}
   404  
   405  	// skip NULL separator
   406  	n++
   407  
   408  	// now argv+n is auxv
   409  	auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize))
   410  	pairs := sysauxv(auxvp[:])
   411  	auxv = auxvp[: pairs*2 : pairs*2]
   412  }
   413  
   414  const (
   415  	_AT_NULL   = 0 // Terminates the vector
   416  	_AT_PAGESZ = 6 // Page size in bytes
   417  )
   418  
   419  func sysauxv(auxv []uintptr) (pairs int) {
   420  	var i int
   421  	for i = 0; auxv[i] != _AT_NULL; i += 2 {
   422  		tag, val := auxv[i], auxv[i+1]
   423  		switch tag {
   424  		case _AT_PAGESZ:
   425  			physPageSize = val
   426  		}
   427  	}
   428  	return i / 2
   429  }
   430  
   431  // raise sends signal to the calling thread.
   432  //
   433  // It must be nosplit because it is used by the signal handler before
   434  // it definitely has a Go stack.
   435  //
   436  //go:nosplit
   437  func raise(sig uint32) {
   438  	lwp_kill(lwp_self(), int(sig))
   439  }
   440  
   441  func signalM(mp *m, sig int) {
   442  	lwp_kill(int32(mp.procid), sig)
   443  }
   444  
   445  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   446  // number.
   447  const sigPerThreadSyscall = 1 << 31
   448  
   449  //go:nosplit
   450  func runPerThreadSyscall() {
   451  	throw("runPerThreadSyscall only valid on linux")
   452  }
   453  

View as plain text