github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/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  	"unsafe"
    10  )
    11  
    12  const (
    13  	_SS_DISABLE  = 4
    14  	_SIG_BLOCK   = 1
    15  	_SIG_UNBLOCK = 2
    16  	_SIG_SETMASK = 3
    17  	_NSIG        = 33
    18  	_SI_USER     = 0
    19  
    20  	// From NetBSD's <sys/ucontext.h>
    21  	_UC_SIGMASK = 0x01
    22  	_UC_CPU     = 0x04
    23  
    24  	_EAGAIN = 35
    25  )
    26  
    27  type mOS struct {
    28  	waitsemacount uint32
    29  }
    30  
    31  //go:noescape
    32  func setitimer(mode int32, new, old *itimerval)
    33  
    34  //go:noescape
    35  func sigaction(sig int32, new, old *sigactiont)
    36  
    37  //go:noescape
    38  func sigaltstack(new, old *sigaltstackt)
    39  
    40  //go:noescape
    41  func sigprocmask(mode int32, new, old *sigset)
    42  
    43  //go:noescape
    44  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    45  
    46  func lwp_tramp()
    47  
    48  func raise(sig int32)
    49  func raiseproc(sig int32)
    50  
    51  //go:noescape
    52  func getcontext(ctxt unsafe.Pointer)
    53  
    54  //go:noescape
    55  func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
    56  
    57  //go:noescape
    58  func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
    59  
    60  //go:noescape
    61  func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
    62  
    63  func lwp_self() int32
    64  
    65  func osyield()
    66  
    67  const (
    68  	_ESRCH     = 3
    69  	_ETIMEDOUT = 60
    70  
    71  	// From NetBSD's <sys/time.h>
    72  	_CLOCK_REALTIME  = 0
    73  	_CLOCK_VIRTUAL   = 1
    74  	_CLOCK_PROF      = 2
    75  	_CLOCK_MONOTONIC = 3
    76  )
    77  
    78  var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
    79  
    80  // From NetBSD's <sys/sysctl.h>
    81  const (
    82  	_CTL_HW      = 6
    83  	_HW_NCPU     = 3
    84  	_HW_PAGESIZE = 7
    85  )
    86  
    87  func getncpu() int32 {
    88  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    89  	out := uint32(0)
    90  	nout := unsafe.Sizeof(out)
    91  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    92  	if ret >= 0 {
    93  		return int32(out)
    94  	}
    95  	return 1
    96  }
    97  
    98  func getPageSize() uintptr {
    99  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
   100  	out := uint32(0)
   101  	nout := unsafe.Sizeof(out)
   102  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   103  	if ret >= 0 {
   104  		return uintptr(out)
   105  	}
   106  	return 0
   107  }
   108  
   109  //go:nosplit
   110  func semacreate(mp *m) {
   111  }
   112  
   113  //go:nosplit
   114  func semasleep(ns int64) int32 {
   115  	_g_ := getg()
   116  
   117  	// Compute sleep deadline.
   118  	var tsp *timespec
   119  	if ns >= 0 {
   120  		var ts timespec
   121  		var nsec int32
   122  		ns += nanotime()
   123  		ts.set_sec(timediv(ns, 1000000000, &nsec))
   124  		ts.set_nsec(nsec)
   125  		tsp = &ts
   126  	}
   127  
   128  	for {
   129  		v := atomic.Load(&_g_.m.waitsemacount)
   130  		if v > 0 {
   131  			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   132  				return 0 // semaphore acquired
   133  			}
   134  			continue
   135  		}
   136  
   137  		// Sleep until unparked by semawakeup or timeout.
   138  		ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
   139  		if ret == _ETIMEDOUT {
   140  			return -1
   141  		}
   142  	}
   143  }
   144  
   145  //go:nosplit
   146  func semawakeup(mp *m) {
   147  	atomic.Xadd(&mp.waitsemacount, 1)
   148  	// From NetBSD's _lwp_unpark(2) manual:
   149  	// "If the target LWP is not currently waiting, it will return
   150  	// immediately upon the next call to _lwp_park()."
   151  	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
   152  	if ret != 0 && ret != _ESRCH {
   153  		// semawakeup can be called on signal stack.
   154  		systemstack(func() {
   155  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   156  		})
   157  	}
   158  }
   159  
   160  // May run with m.p==nil, so write barriers are not allowed.
   161  //go:nowritebarrier
   162  func newosproc(mp *m, stk unsafe.Pointer) {
   163  	if false {
   164  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   165  	}
   166  
   167  	var uc ucontextt
   168  	getcontext(unsafe.Pointer(&uc))
   169  
   170  	uc.uc_flags = _UC_SIGMASK | _UC_CPU
   171  	uc.uc_link = nil
   172  	uc.uc_sigmask = sigset_all
   173  
   174  	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart))
   175  
   176  	ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
   177  	if ret < 0 {
   178  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   179  		if ret == -_EAGAIN {
   180  			println("runtime: may need to increase max user processes (ulimit -p)")
   181  		}
   182  		throw("runtime.newosproc")
   183  	}
   184  }
   185  
   186  // netbsdMStart is the function call that starts executing a newly
   187  // created thread. On NetBSD, a new thread inherits the signal stack
   188  // of the creating thread. That confuses minit, so we remove that
   189  // signal stack here before calling the regular mstart. It's a bit
   190  // baroque to remove a signal stack here only to add one in minit, but
   191  // it's a simple change that keeps NetBSD working like other OS's.
   192  // At this point all signals are blocked, so there is no race.
   193  //go:nosplit
   194  func netbsdMstart() {
   195  	signalstack(nil)
   196  	mstart()
   197  }
   198  
   199  func osinit() {
   200  	ncpu = getncpu()
   201  	physPageSize = getPageSize()
   202  }
   203  
   204  var urandom_dev = []byte("/dev/urandom\x00")
   205  
   206  //go:nosplit
   207  func getRandomData(r []byte) {
   208  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   209  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   210  	closefd(fd)
   211  	extendRandom(r, int(n))
   212  }
   213  
   214  func goenvs() {
   215  	goenvs_unix()
   216  }
   217  
   218  // Called to initialize a new m (including the bootstrap m).
   219  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   220  func mpreinit(mp *m) {
   221  	mp.gsignal = malg(32 * 1024)
   222  	mp.gsignal.m = mp
   223  }
   224  
   225  //go:nosplit
   226  func msigsave(mp *m) {
   227  	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
   228  }
   229  
   230  //go:nosplit
   231  func msigrestore(sigmask sigset) {
   232  	sigprocmask(_SIG_SETMASK, &sigmask, nil)
   233  }
   234  
   235  //go:nosplit
   236  func sigblock() {
   237  	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
   238  }
   239  
   240  // Called to initialize a new m (including the bootstrap m).
   241  // Called on the new thread, cannot allocate memory.
   242  func minit() {
   243  	_g_ := getg()
   244  	_g_.m.procid = uint64(lwp_self())
   245  
   246  	// Initialize signal handling.
   247  
   248  	// On NetBSD a thread created by pthread_create inherits the
   249  	// signal stack of the creating thread. We always create a
   250  	// new signal stack here, to avoid having two Go threads using
   251  	// the same signal stack. This breaks the case of a thread
   252  	// created in C that calls sigaltstack and then calls a Go
   253  	// function, because we will lose track of the C code's
   254  	// sigaltstack, but it's the best we can do.
   255  	signalstack(&_g_.m.gsignal.stack)
   256  	_g_.m.newSigstack = true
   257  
   258  	// restore signal mask from m.sigmask and unblock essential signals
   259  	nmask := _g_.m.sigmask
   260  	for i := range sigtable {
   261  		if sigtable[i].flags&_SigUnblock != 0 {
   262  			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   263  		}
   264  	}
   265  	sigprocmask(_SIG_SETMASK, &nmask, nil)
   266  }
   267  
   268  // Called from dropm to undo the effect of an minit.
   269  //go:nosplit
   270  func unminit() {
   271  	if getg().m.newSigstack {
   272  		signalstack(nil)
   273  	}
   274  }
   275  
   276  func memlimit() uintptr {
   277  	return 0
   278  }
   279  
   280  func sigtramp()
   281  
   282  type sigactiont struct {
   283  	sa_sigaction uintptr
   284  	sa_mask      sigset
   285  	sa_flags     int32
   286  }
   287  
   288  //go:nosplit
   289  //go:nowritebarrierrec
   290  func setsig(i int32, fn uintptr, restart bool) {
   291  	var sa sigactiont
   292  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   293  	if restart {
   294  		sa.sa_flags |= _SA_RESTART
   295  	}
   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 int32) {
   307  	throw("setsigstack")
   308  }
   309  
   310  //go:nosplit
   311  //go:nowritebarrierrec
   312  func getsig(i int32) uintptr {
   313  	var sa sigactiont
   314  	sigaction(i, nil, &sa)
   315  	if sa.sa_sigaction == funcPC(sigtramp) {
   316  		return funcPC(sighandler)
   317  	}
   318  	return sa.sa_sigaction
   319  }
   320  
   321  //go:nosplit
   322  func signalstack(s *stack) {
   323  	var st sigaltstackt
   324  	if s == nil {
   325  		st.ss_flags = _SS_DISABLE
   326  	} else {
   327  		st.ss_sp = s.lo
   328  		st.ss_size = s.hi - s.lo
   329  		st.ss_flags = 0
   330  	}
   331  	sigaltstack(&st, nil)
   332  }
   333  
   334  //go:nosplit
   335  //go:nowritebarrierrec
   336  func updatesigmask(m sigmask) {
   337  	var mask sigset
   338  	copy(mask.__bits[:], m[:])
   339  	sigprocmask(_SIG_SETMASK, &mask, nil)
   340  }
   341  
   342  func unblocksig(sig int32) {
   343  	var mask sigset
   344  	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
   345  	sigprocmask(_SIG_UNBLOCK, &mask, nil)
   346  }