Black Lives Matter. Support the Equal Justice Initiative.

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

View as plain text