github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/os_openbsd.go (about)

     1  // Copyright 2011 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  type mOS struct {
    14  	waitsemacount uint32
    15  }
    16  
    17  //go:noescape
    18  func setitimer(mode int32, new, old *itimerval)
    19  
    20  //go:noescape
    21  func sigaction(sig uint32, new, old *sigactiont)
    22  
    23  //go:noescape
    24  func sigaltstack(new, old *stackt)
    25  
    26  //go:noescape
    27  func obsdsigprocmask(how int32, new sigset) sigset
    28  
    29  //go:nosplit
    30  //go:nowritebarrierrec
    31  func sigprocmask(how int32, new, old *sigset) {
    32  	n := sigset(0)
    33  	if new != nil {
    34  		n = *new
    35  	}
    36  	r := obsdsigprocmask(how, n)
    37  	if old != nil {
    38  		*old = r
    39  	}
    40  }
    41  
    42  //go:noescape
    43  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    44  
    45  func raiseproc(sig uint32)
    46  
    47  func getthrid() int32
    48  func thrkill(tid int32, sig int)
    49  
    50  //go:noescape
    51  func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
    52  
    53  //go:noescape
    54  func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
    55  
    56  //go:noescape
    57  func thrwakeup(ident uintptr, n int32) int32
    58  
    59  func osyield()
    60  
    61  func kqueue() int32
    62  
    63  //go:noescape
    64  func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    65  
    66  func pipe() (r, w int32, errno int32)
    67  func pipe2(flags int32) (r, w int32, errno int32)
    68  func closeonexec(fd int32)
    69  func setNonblock(fd int32)
    70  
    71  const (
    72  	_ESRCH		= 3
    73  	_EWOULDBLOCK	= _EAGAIN
    74  	_ENOTSUP	= 91
    75  
    76  	// From OpenBSD's sys/time.h
    77  	_CLOCK_REALTIME		= 0
    78  	_CLOCK_VIRTUAL		= 1
    79  	_CLOCK_PROF		= 2
    80  	_CLOCK_MONOTONIC	= 3
    81  )
    82  
    83  type sigset uint32
    84  
    85  var sigset_all = ^sigset(0)
    86  
    87  // From OpenBSD's <sys/sysctl.h>
    88  const (
    89  	_CTL_KERN	= 1
    90  	_KERN_OSREV	= 3
    91  
    92  	_CTL_HW		= 6
    93  	_HW_NCPU	= 3
    94  	_HW_PAGESIZE	= 7
    95  	_HW_NCPUONLINE	= 25
    96  )
    97  
    98  func sysctlInt(mib []uint32) (int32, bool) {
    99  	var out int32
   100  	nout := unsafe.Sizeof(out)
   101  	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
   102  	if ret < 0 {
   103  		return 0, false
   104  	}
   105  	return out, true
   106  }
   107  
   108  func getncpu() int32 {
   109  	// Try hw.ncpuonline first because hw.ncpu would report a number twice as
   110  	// high as the actual CPUs running on OpenBSD 6.4 with hyperthreading
   111  	// disabled (hw.smt=0). See https://golang.org/issue/30127
   112  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok {
   113  		return int32(n)
   114  	}
   115  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok {
   116  		return int32(n)
   117  	}
   118  	return 1
   119  }
   120  
   121  func getPageSize() uintptr {
   122  	if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok {
   123  		return uintptr(ps)
   124  	}
   125  	return 0
   126  }
   127  
   128  func getOSRev() int {
   129  	if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok {
   130  		return int(osrev)
   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  
   143  	// Compute sleep deadline.
   144  	var tsp *timespec
   145  	if ns >= 0 {
   146  		var ts timespec
   147  		ts.setNsec(ns + nanotime())
   148  		tsp = &ts
   149  	}
   150  
   151  	for {
   152  		v := atomic.Load(&_g_.m.waitsemacount)
   153  		if v > 0 {
   154  			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   155  				return 0	// semaphore acquired
   156  			}
   157  			continue
   158  		}
   159  
   160  		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
   161  		//
   162  		// From OpenBSD's __thrsleep(2) manual:
   163  		// "The abort argument, if not NULL, points to an int that will
   164  		// be examined [...] immediately before blocking. If that int
   165  		// is non-zero then __thrsleep() will immediately return EINTR
   166  		// without blocking."
   167  		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
   168  		if ret == _EWOULDBLOCK {
   169  			return -1
   170  		}
   171  	}
   172  }
   173  
   174  //go:nosplit
   175  func semawakeup(mp *m) {
   176  	atomic.Xadd(&mp.waitsemacount, 1)
   177  	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
   178  	if ret != 0 && ret != _ESRCH {
   179  		// semawakeup can be called on signal stack.
   180  		systemstack(func() {
   181  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   182  		})
   183  	}
   184  }
   185  
   186  // May run with m.p==nil, so write barriers are not allowed.
   187  //go:nowritebarrier
   188  func newosproc(mp *m) {
   189  	stk := unsafe.Pointer(mp.g0.stack.hi)
   190  	if false {
   191  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   192  	}
   193  
   194  	// Stack pointer must point inside stack area (as marked with MAP_STACK),
   195  	// rather than at the top of it.
   196  	param := tforkt{
   197  		tf_tcb:		unsafe.Pointer(&mp.tls[0]),
   198  		tf_tid:		nil,	// minit will record tid
   199  		tf_stack:	uintptr(stk) - sys.PtrSize,
   200  	}
   201  
   202  	var oset sigset
   203  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   204  	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
   205  	sigprocmask(_SIG_SETMASK, &oset, nil)
   206  
   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  func osinit() {
   217  	ncpu = getncpu()
   218  	physPageSize = getPageSize()
   219  	haveMapStack = getOSRev() >= 201805	// OpenBSD 6.3
   220  }
   221  
   222  var urandom_dev = []byte("/dev/urandom\x00")
   223  
   224  //go:nosplit
   225  func getRandomData(r []byte) {
   226  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   227  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   228  	closefd(fd)
   229  	extendRandom(r, int(n))
   230  }
   231  
   232  func goenvs() {
   233  	goenvs_unix()
   234  }
   235  
   236  // Called to initialize a new m (including the bootstrap m).
   237  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   238  func mpreinit(mp *m) {
   239  	mp.gsignal = malg(32 * 1024)
   240  	mp.gsignal.m = mp
   241  }
   242  
   243  // Called to initialize a new m (including the bootstrap m).
   244  // Called on the new thread, can not allocate memory.
   245  func minit() {
   246  	getg().m.procid = uint64(getthrid())
   247  	minitSignals()
   248  }
   249  
   250  // Called from dropm to undo the effect of an minit.
   251  //go:nosplit
   252  func unminit() {
   253  	unminitSignals()
   254  }
   255  
   256  func sigtramp()
   257  
   258  type sigactiont struct {
   259  	sa_sigaction	uintptr
   260  	sa_mask		uint32
   261  	sa_flags	int32
   262  }
   263  
   264  //go:nosplit
   265  //go:nowritebarrierrec
   266  func setsig(i uint32, fn uintptr) {
   267  	var sa sigactiont
   268  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   269  	sa.sa_mask = uint32(sigset_all)
   270  	if fn == funcPC(sighandler) {
   271  		fn = funcPC(sigtramp)
   272  	}
   273  	sa.sa_sigaction = fn
   274  	sigaction(i, &sa, nil)
   275  }
   276  
   277  //go:nosplit
   278  //go:nowritebarrierrec
   279  func setsigstack(i uint32) {
   280  	throw("setsigstack")
   281  }
   282  
   283  //go:nosplit
   284  //go:nowritebarrierrec
   285  func getsig(i uint32) uintptr {
   286  	var sa sigactiont
   287  	sigaction(i, nil, &sa)
   288  	return sa.sa_sigaction
   289  }
   290  
   291  // setSignaltstackSP sets the ss_sp field of a stackt.
   292  //go:nosplit
   293  func setSignalstackSP(s *stackt, sp uintptr) {
   294  	s.ss_sp = sp
   295  }
   296  
   297  //go:nosplit
   298  //go:nowritebarrierrec
   299  func sigaddset(mask *sigset, i int) {
   300  	*mask |= 1 << (uint32(i) - 1)
   301  }
   302  
   303  func sigdelset(mask *sigset, i int) {
   304  	*mask &^= 1 << (uint32(i) - 1)
   305  }
   306  
   307  //go:nosplit
   308  func (c *sigctxt) fixsigcode(sig uint32) {
   309  }
   310  
   311  var haveMapStack = false
   312  
   313  func osStackAlloc(s *mspan) {
   314  	// OpenBSD 6.4+ requires that stacks be mapped with MAP_STACK.
   315  	// It will check this on entry to system calls, traps, and
   316  	// when switching to the alternate system stack.
   317  	//
   318  	// This function is called before s is used for any data, so
   319  	// it's safe to simply re-map it.
   320  	osStackRemap(s, _MAP_STACK)
   321  }
   322  
   323  func osStackFree(s *mspan) {
   324  	// Undo MAP_STACK.
   325  	osStackRemap(s, 0)
   326  }
   327  
   328  func osStackRemap(s *mspan, flags int32) {
   329  	if !haveMapStack {
   330  		// OpenBSD prior to 6.3 did not have MAP_STACK and so
   331  		// the following mmap will fail. But it also didn't
   332  		// require MAP_STACK (obviously), so there's no need
   333  		// to do the mmap.
   334  		return
   335  	}
   336  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   337  	if err != 0 || uintptr(a) != s.base() {
   338  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   339  		throw("remapping stack memory failed")
   340  	}
   341  }
   342  
   343  func raise(sig uint32) {
   344  	thrkill(getthrid(), int(sig))
   345  }
   346  
   347  func signalM(mp *m, sig int) {
   348  	thrkill(int32(mp.procid), sig)
   349  }