...
Run Format

Source file src/runtime/os_openbsd.go

Documentation: runtime

     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  	"runtime/internal/sys"
    10  	"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 raise(sig uint32)
    46  func raiseproc(sig uint32)
    47  
    48  //go:noescape
    49  func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
    50  
    51  //go:noescape
    52  func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
    53  
    54  //go:noescape
    55  func thrwakeup(ident uintptr, n int32) int32
    56  
    57  func osyield()
    58  
    59  func kqueue() int32
    60  
    61  //go:noescape
    62  func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
    63  func closeonexec(fd int32)
    64  
    65  const (
    66  	_ESRCH       = 3
    67  	_EAGAIN      = 35
    68  	_EWOULDBLOCK = _EAGAIN
    69  	_ENOTSUP     = 91
    70  
    71  	// From OpenBSD's sys/time.h
    72  	_CLOCK_REALTIME  = 0
    73  	_CLOCK_VIRTUAL   = 1
    74  	_CLOCK_PROF      = 2
    75  	_CLOCK_MONOTONIC = 3
    76  )
    77  
    78  type sigset uint32
    79  
    80  var sigset_all = ^sigset(0)
    81  
    82  // From OpenBSD's <sys/sysctl.h>
    83  const (
    84  	_CTL_KERN   = 1
    85  	_KERN_OSREV = 3
    86  
    87  	_CTL_HW      = 6
    88  	_HW_NCPU     = 3
    89  	_HW_PAGESIZE = 7
    90  )
    91  
    92  func sysctlInt(mib []uint32) (int32, bool) {
    93  	var out int32
    94  	nout := unsafe.Sizeof(out)
    95  	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    96  	if ret < 0 {
    97  		return 0, false
    98  	}
    99  	return out, true
   100  }
   101  
   102  func getncpu() int32 {
   103  	// Fetch hw.ncpu via sysctl.
   104  	if ncpu, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok {
   105  		return int32(ncpu)
   106  	}
   107  	return 1
   108  }
   109  
   110  func getPageSize() uintptr {
   111  	if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok {
   112  		return uintptr(ps)
   113  	}
   114  	return 0
   115  }
   116  
   117  func getOSRev() int {
   118  	if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok {
   119  		return int(osrev)
   120  	}
   121  	return 0
   122  }
   123  
   124  //go:nosplit
   125  func semacreate(mp *m) {
   126  }
   127  
   128  //go:nosplit
   129  func semasleep(ns int64) int32 {
   130  	_g_ := getg()
   131  
   132  	// Compute sleep deadline.
   133  	var tsp *timespec
   134  	if ns >= 0 {
   135  		var ts timespec
   136  		var nsec int32
   137  		ns += nanotime()
   138  		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
   139  		ts.set_nsec(nsec)
   140  		tsp = &ts
   141  	}
   142  
   143  	for {
   144  		v := atomic.Load(&_g_.m.waitsemacount)
   145  		if v > 0 {
   146  			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   147  				return 0 // semaphore acquired
   148  			}
   149  			continue
   150  		}
   151  
   152  		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
   153  		//
   154  		// From OpenBSD's __thrsleep(2) manual:
   155  		// "The abort argument, if not NULL, points to an int that will
   156  		// be examined [...] immediately before blocking. If that int
   157  		// is non-zero then __thrsleep() will immediately return EINTR
   158  		// without blocking."
   159  		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
   160  		if ret == _EWOULDBLOCK {
   161  			return -1
   162  		}
   163  	}
   164  }
   165  
   166  //go:nosplit
   167  func semawakeup(mp *m) {
   168  	atomic.Xadd(&mp.waitsemacount, 1)
   169  	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
   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  	// Stack pointer must point inside stack area (as marked with MAP_STACK),
   187  	// rather than at the top of it.
   188  	param := tforkt{
   189  		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
   190  		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
   191  		tf_stack: uintptr(stk) - sys.PtrSize,
   192  	}
   193  
   194  	var oset sigset
   195  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   196  	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
   197  	sigprocmask(_SIG_SETMASK, &oset, nil)
   198  
   199  	if ret < 0 {
   200  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   201  		if ret == -_EAGAIN {
   202  			println("runtime: may need to increase max user processes (ulimit -p)")
   203  		}
   204  		throw("runtime.newosproc")
   205  	}
   206  }
   207  
   208  func osinit() {
   209  	ncpu = getncpu()
   210  	physPageSize = getPageSize()
   211  	haveMapStack = getOSRev() >= 201805 // OpenBSD 6.3
   212  }
   213  
   214  var urandom_dev = []byte("/dev/urandom\x00")
   215  
   216  //go:nosplit
   217  func getRandomData(r []byte) {
   218  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   219  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   220  	closefd(fd)
   221  	extendRandom(r, int(n))
   222  }
   223  
   224  func goenvs() {
   225  	goenvs_unix()
   226  }
   227  
   228  // Called to initialize a new m (including the bootstrap m).
   229  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   230  func mpreinit(mp *m) {
   231  	mp.gsignal = malg(32 * 1024)
   232  	mp.gsignal.m = mp
   233  }
   234  
   235  // Called to initialize a new m (including the bootstrap m).
   236  // Called on the new thread, can not allocate memory.
   237  func minit() {
   238  	// m.procid is a uint64, but tfork writes an int32. Fix it up.
   239  	_g_ := getg()
   240  	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
   241  
   242  	minitSignals()
   243  }
   244  
   245  // Called from dropm to undo the effect of an minit.
   246  //go:nosplit
   247  func unminit() {
   248  	unminitSignals()
   249  }
   250  
   251  func sigtramp()
   252  
   253  type sigactiont struct {
   254  	sa_sigaction uintptr
   255  	sa_mask      uint32
   256  	sa_flags     int32
   257  }
   258  
   259  //go:nosplit
   260  //go:nowritebarrierrec
   261  func setsig(i uint32, fn uintptr) {
   262  	var sa sigactiont
   263  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   264  	sa.sa_mask = uint32(sigset_all)
   265  	if fn == funcPC(sighandler) {
   266  		fn = funcPC(sigtramp)
   267  	}
   268  	sa.sa_sigaction = fn
   269  	sigaction(i, &sa, nil)
   270  }
   271  
   272  //go:nosplit
   273  //go:nowritebarrierrec
   274  func setsigstack(i uint32) {
   275  	throw("setsigstack")
   276  }
   277  
   278  //go:nosplit
   279  //go:nowritebarrierrec
   280  func getsig(i uint32) uintptr {
   281  	var sa sigactiont
   282  	sigaction(i, nil, &sa)
   283  	return sa.sa_sigaction
   284  }
   285  
   286  // setSignaltstackSP sets the ss_sp field of a stackt.
   287  //go:nosplit
   288  func setSignalstackSP(s *stackt, sp uintptr) {
   289  	s.ss_sp = sp
   290  }
   291  
   292  //go:nosplit
   293  //go:nowritebarrierrec
   294  func sigaddset(mask *sigset, i int) {
   295  	*mask |= 1 << (uint32(i) - 1)
   296  }
   297  
   298  func sigdelset(mask *sigset, i int) {
   299  	*mask &^= 1 << (uint32(i) - 1)
   300  }
   301  
   302  func (c *sigctxt) fixsigcode(sig uint32) {
   303  }
   304  
   305  var haveMapStack = false
   306  
   307  func osStackAlloc(s *mspan) {
   308  	// OpenBSD 6.4+ requires that stacks be mapped with MAP_STACK.
   309  	// It will check this on entry to system calls, traps, and
   310  	// when switching to the alternate system stack.
   311  	//
   312  	// This function is called before s is used for any data, so
   313  	// it's safe to simply re-map it.
   314  	osStackRemap(s, _MAP_STACK)
   315  }
   316  
   317  func osStackFree(s *mspan) {
   318  	// Undo MAP_STACK.
   319  	osStackRemap(s, 0)
   320  }
   321  
   322  func osStackRemap(s *mspan, flags int32) {
   323  	if !haveMapStack {
   324  		// OpenBSD prior to 6.3 did not have MAP_STACK and so
   325  		// the following mmap will fail. But it also didn't
   326  		// require MAP_STACK (obviously), so there's no need
   327  		// to do the mmap.
   328  		return
   329  	}
   330  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   331  	if err != 0 || uintptr(a) != s.base() {
   332  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   333  		throw("remapping stack memory failed")
   334  	}
   335  }
   336  

View as plain text