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