...
Run Format

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

View as plain text