github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/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  	"runtime/internal/atomic"
     9  	"unsafe"
    10  )
    11  
    12  type mOS struct {
    13  	waitsemacount uint32
    14  }
    15  
    16  //go:noescape
    17  func setitimer(mode int32, new, old *itimerval)
    18  
    19  //go:noescape
    20  func sigaction(sig int32, new, old *sigactiont)
    21  
    22  //go:noescape
    23  func sigaltstack(new, old *stackt)
    24  
    25  //go:noescape
    26  func sigprocmask(mode int32, new sigset) sigset
    27  
    28  //go:noescape
    29  func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
    30  
    31  func raise(sig int32)
    32  func raiseproc(sig int32)
    33  
    34  //go:noescape
    35  func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
    36  
    37  //go:noescape
    38  func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
    39  
    40  //go:noescape
    41  func thrwakeup(ident uintptr, n int32) int32
    42  
    43  func osyield()
    44  
    45  const (
    46  	_ESRCH       = 3
    47  	_EAGAIN      = 35
    48  	_EWOULDBLOCK = _EAGAIN
    49  	_ENOTSUP     = 91
    50  
    51  	// From OpenBSD's sys/time.h
    52  	_CLOCK_REALTIME  = 0
    53  	_CLOCK_VIRTUAL   = 1
    54  	_CLOCK_PROF      = 2
    55  	_CLOCK_MONOTONIC = 3
    56  )
    57  
    58  type sigset uint32
    59  
    60  const (
    61  	sigset_none = sigset(0)
    62  	sigset_all  = ^sigset(0)
    63  )
    64  
    65  // From OpenBSD's <sys/sysctl.h>
    66  const (
    67  	_CTL_HW      = 6
    68  	_HW_NCPU     = 3
    69  	_HW_PAGESIZE = 7
    70  )
    71  
    72  func getncpu() int32 {
    73  	mib := [2]uint32{_CTL_HW, _HW_NCPU}
    74  	out := uint32(0)
    75  	nout := unsafe.Sizeof(out)
    76  
    77  	// Fetch hw.ncpu via sysctl.
    78  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    79  	if ret >= 0 {
    80  		return int32(out)
    81  	}
    82  	return 1
    83  }
    84  
    85  func getPageSize() uintptr {
    86  	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
    87  	out := uint32(0)
    88  	nout := unsafe.Sizeof(out)
    89  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    90  	if ret >= 0 {
    91  		return uintptr(out)
    92  	}
    93  	return 0
    94  }
    95  
    96  //go:nosplit
    97  func semacreate(mp *m) {
    98  }
    99  
   100  //go:nosplit
   101  func semasleep(ns int64) int32 {
   102  	_g_ := getg()
   103  
   104  	// Compute sleep deadline.
   105  	var tsp *timespec
   106  	if ns >= 0 {
   107  		var ts timespec
   108  		var nsec int32
   109  		ns += nanotime()
   110  		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
   111  		ts.set_nsec(nsec)
   112  		tsp = &ts
   113  	}
   114  
   115  	for {
   116  		v := atomic.Load(&_g_.m.waitsemacount)
   117  		if v > 0 {
   118  			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   119  				return 0 // semaphore acquired
   120  			}
   121  			continue
   122  		}
   123  
   124  		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
   125  		//
   126  		// From OpenBSD's __thrsleep(2) manual:
   127  		// "The abort argument, if not NULL, points to an int that will
   128  		// be examined [...] immediately before blocking. If that int
   129  		// is non-zero then __thrsleep() will immediately return EINTR
   130  		// without blocking."
   131  		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
   132  		if ret == _EWOULDBLOCK {
   133  			return -1
   134  		}
   135  	}
   136  }
   137  
   138  //go:nosplit
   139  func semawakeup(mp *m) {
   140  	atomic.Xadd(&mp.waitsemacount, 1)
   141  	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
   142  	if ret != 0 && ret != _ESRCH {
   143  		// semawakeup can be called on signal stack.
   144  		systemstack(func() {
   145  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   146  		})
   147  	}
   148  }
   149  
   150  // May run with m.p==nil, so write barriers are not allowed.
   151  //go:nowritebarrier
   152  func newosproc(mp *m, stk unsafe.Pointer) {
   153  	if false {
   154  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   155  	}
   156  
   157  	param := tforkt{
   158  		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
   159  		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
   160  		tf_stack: uintptr(stk),
   161  	}
   162  
   163  	oset := sigprocmask(_SIG_SETMASK, sigset_all)
   164  	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
   165  	sigprocmask(_SIG_SETMASK, oset)
   166  
   167  	if ret < 0 {
   168  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   169  		if ret == -_EAGAIN {
   170  			println("runtime: may need to increase max user processes (ulimit -p)")
   171  		}
   172  		throw("runtime.newosproc")
   173  	}
   174  }
   175  
   176  func osinit() {
   177  	ncpu = getncpu()
   178  	physPageSize = getPageSize()
   179  }
   180  
   181  var urandom_dev = []byte("/dev/urandom\x00")
   182  
   183  //go:nosplit
   184  func getRandomData(r []byte) {
   185  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   186  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   187  	closefd(fd)
   188  	extendRandom(r, int(n))
   189  }
   190  
   191  func goenvs() {
   192  	goenvs_unix()
   193  }
   194  
   195  // Called to initialize a new m (including the bootstrap m).
   196  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   197  func mpreinit(mp *m) {
   198  	mp.gsignal = malg(32 * 1024)
   199  	mp.gsignal.m = mp
   200  }
   201  
   202  //go:nosplit
   203  func msigsave(mp *m) {
   204  	mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
   205  }
   206  
   207  //go:nosplit
   208  func msigrestore(sigmask sigset) {
   209  	sigprocmask(_SIG_SETMASK, sigmask)
   210  }
   211  
   212  //go:nosplit
   213  func sigblock() {
   214  	sigprocmask(_SIG_SETMASK, sigset_all)
   215  }
   216  
   217  // Called to initialize a new m (including the bootstrap m).
   218  // Called on the new thread, can not allocate memory.
   219  func minit() {
   220  	_g_ := getg()
   221  
   222  	// m.procid is a uint64, but tfork writes an int32. Fix it up.
   223  	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
   224  
   225  	// Initialize signal handling
   226  	var st stackt
   227  	sigaltstack(nil, &st)
   228  	if st.ss_flags&_SS_DISABLE != 0 {
   229  		signalstack(&_g_.m.gsignal.stack)
   230  		_g_.m.newSigstack = true
   231  	} else {
   232  		// Use existing signal stack.
   233  		stsp := uintptr(unsafe.Pointer(st.ss_sp))
   234  		_g_.m.gsignal.stack.lo = stsp
   235  		_g_.m.gsignal.stack.hi = stsp + st.ss_size
   236  		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
   237  		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
   238  		_g_.m.gsignal.stackAlloc = st.ss_size
   239  		_g_.m.newSigstack = false
   240  	}
   241  
   242  	// restore signal mask from m.sigmask and unblock essential signals
   243  	nmask := _g_.m.sigmask
   244  	for i := range sigtable {
   245  		if sigtable[i].flags&_SigUnblock != 0 {
   246  			nmask &^= 1 << (uint32(i) - 1)
   247  		}
   248  	}
   249  	sigprocmask(_SIG_SETMASK, nmask)
   250  }
   251  
   252  // Called from dropm to undo the effect of an minit.
   253  //go:nosplit
   254  func unminit() {
   255  	if getg().m.newSigstack {
   256  		signalstack(nil)
   257  	}
   258  }
   259  
   260  func memlimit() uintptr {
   261  	return 0
   262  }
   263  
   264  func sigtramp()
   265  
   266  type sigactiont struct {
   267  	sa_sigaction uintptr
   268  	sa_mask      uint32
   269  	sa_flags     int32
   270  }
   271  
   272  //go:nosplit
   273  //go:nowritebarrierrec
   274  func setsig(i int32, fn uintptr, restart bool) {
   275  	var sa sigactiont
   276  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   277  	if restart {
   278  		sa.sa_flags |= _SA_RESTART
   279  	}
   280  	sa.sa_mask = uint32(sigset_all)
   281  	if fn == funcPC(sighandler) {
   282  		fn = funcPC(sigtramp)
   283  	}
   284  	sa.sa_sigaction = fn
   285  	sigaction(i, &sa, nil)
   286  }
   287  
   288  //go:nosplit
   289  //go:nowritebarrierrec
   290  func setsigstack(i int32) {
   291  	throw("setsigstack")
   292  }
   293  
   294  //go:nosplit
   295  //go:nowritebarrierrec
   296  func getsig(i int32) uintptr {
   297  	var sa sigactiont
   298  	sigaction(i, nil, &sa)
   299  	if sa.sa_sigaction == funcPC(sigtramp) {
   300  		return funcPC(sighandler)
   301  	}
   302  	return sa.sa_sigaction
   303  }
   304  
   305  //go:nosplit
   306  func signalstack(s *stack) {
   307  	var st stackt
   308  	if s == nil {
   309  		st.ss_flags = _SS_DISABLE
   310  	} else {
   311  		st.ss_sp = s.lo
   312  		st.ss_size = s.hi - s.lo
   313  		st.ss_flags = 0
   314  	}
   315  	sigaltstack(&st, nil)
   316  }
   317  
   318  //go:nosplit
   319  //go:nowritebarrierrec
   320  func updatesigmask(m sigmask) {
   321  	sigprocmask(_SIG_SETMASK, sigset(m[0]))
   322  }
   323  
   324  func unblocksig(sig int32) {
   325  	mask := sigset(1) << (uint32(sig) - 1)
   326  	sigprocmask(_SIG_UNBLOCK, mask)
   327  }