github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/os_netbsd.go (about)

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