Black Lives Matter. Support the Equal Justice Initiative.

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  	"unsafe"
    10  )
    11  
    12  type mOS struct {
    13  	waitsemacount uint32
    14  }
    15  
    16  const (
    17  	_ESRCH       = 3
    18  	_EWOULDBLOCK = _EAGAIN
    19  	_ENOTSUP     = 91
    20  
    21  	// From OpenBSD's sys/time.h
    22  	_CLOCK_REALTIME  = 0
    23  	_CLOCK_VIRTUAL   = 1
    24  	_CLOCK_PROF      = 2
    25  	_CLOCK_MONOTONIC = 3
    26  )
    27  
    28  type sigset uint32
    29  
    30  var sigset_all = ^sigset(0)
    31  
    32  // From OpenBSD's <sys/sysctl.h>
    33  const (
    34  	_CTL_KERN   = 1
    35  	_KERN_OSREV = 3
    36  
    37  	_CTL_HW        = 6
    38  	_HW_NCPU       = 3
    39  	_HW_PAGESIZE   = 7
    40  	_HW_NCPUONLINE = 25
    41  )
    42  
    43  func sysctlInt(mib []uint32) (int32, bool) {
    44  	var out int32
    45  	nout := unsafe.Sizeof(out)
    46  	ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    47  	if ret < 0 {
    48  		return 0, false
    49  	}
    50  	return out, true
    51  }
    52  
    53  func getncpu() int32 {
    54  	// Try hw.ncpuonline first because hw.ncpu would report a number twice as
    55  	// high as the actual CPUs running on OpenBSD 6.4 with hyperthreading
    56  	// disabled (hw.smt=0). See https://golang.org/issue/30127
    57  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok {
    58  		return int32(n)
    59  	}
    60  	if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok {
    61  		return int32(n)
    62  	}
    63  	return 1
    64  }
    65  
    66  func getPageSize() uintptr {
    67  	if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok {
    68  		return uintptr(ps)
    69  	}
    70  	return 0
    71  }
    72  
    73  func getOSRev() int {
    74  	if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok {
    75  		return int(osrev)
    76  	}
    77  	return 0
    78  }
    79  
    80  //go:nosplit
    81  func semacreate(mp *m) {
    82  }
    83  
    84  //go:nosplit
    85  func semasleep(ns int64) int32 {
    86  	_g_ := getg()
    87  
    88  	// Compute sleep deadline.
    89  	var tsp *timespec
    90  	if ns >= 0 {
    91  		var ts timespec
    92  		ts.setNsec(ns + nanotime())
    93  		tsp = &ts
    94  	}
    95  
    96  	for {
    97  		v := atomic.Load(&_g_.m.waitsemacount)
    98  		if v > 0 {
    99  			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
   100  				return 0 // semaphore acquired
   101  			}
   102  			continue
   103  		}
   104  
   105  		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
   106  		//
   107  		// From OpenBSD's __thrsleep(2) manual:
   108  		// "The abort argument, if not NULL, points to an int that will
   109  		// be examined [...] immediately before blocking. If that int
   110  		// is non-zero then __thrsleep() will immediately return EINTR
   111  		// without blocking."
   112  		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
   113  		if ret == _EWOULDBLOCK {
   114  			return -1
   115  		}
   116  	}
   117  }
   118  
   119  //go:nosplit
   120  func semawakeup(mp *m) {
   121  	atomic.Xadd(&mp.waitsemacount, 1)
   122  	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
   123  	if ret != 0 && ret != _ESRCH {
   124  		// semawakeup can be called on signal stack.
   125  		systemstack(func() {
   126  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   127  		})
   128  	}
   129  }
   130  
   131  func osinit() {
   132  	ncpu = getncpu()
   133  	physPageSize = getPageSize()
   134  	haveMapStack = getOSRev() >= 201805 // OpenBSD 6.3
   135  }
   136  
   137  var urandom_dev = []byte("/dev/urandom\x00")
   138  
   139  //go:nosplit
   140  func getRandomData(r []byte) {
   141  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   142  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   143  	closefd(fd)
   144  	extendRandom(r, int(n))
   145  }
   146  
   147  func goenvs() {
   148  	goenvs_unix()
   149  }
   150  
   151  // Called to initialize a new m (including the bootstrap m).
   152  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   153  func mpreinit(mp *m) {
   154  	gsignalSize := int32(32 * 1024)
   155  	if GOARCH == "mips64" {
   156  		gsignalSize = int32(64 * 1024)
   157  	}
   158  	mp.gsignal = malg(gsignalSize)
   159  	mp.gsignal.m = mp
   160  }
   161  
   162  // Called to initialize a new m (including the bootstrap m).
   163  // Called on the new thread, can not allocate memory.
   164  func minit() {
   165  	getg().m.procid = uint64(getthrid())
   166  	minitSignals()
   167  }
   168  
   169  // Called from dropm to undo the effect of an minit.
   170  //go:nosplit
   171  func unminit() {
   172  	unminitSignals()
   173  }
   174  
   175  // Called from exitm, but not from drop, to undo the effect of thread-owned
   176  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   177  func mdestroy(mp *m) {
   178  }
   179  
   180  func sigtramp()
   181  
   182  type sigactiont struct {
   183  	sa_sigaction uintptr
   184  	sa_mask      uint32
   185  	sa_flags     int32
   186  }
   187  
   188  //go:nosplit
   189  //go:nowritebarrierrec
   190  func setsig(i uint32, fn uintptr) {
   191  	var sa sigactiont
   192  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   193  	sa.sa_mask = uint32(sigset_all)
   194  	if fn == funcPC(sighandler) {
   195  		fn = funcPC(sigtramp)
   196  	}
   197  	sa.sa_sigaction = fn
   198  	sigaction(i, &sa, nil)
   199  }
   200  
   201  //go:nosplit
   202  //go:nowritebarrierrec
   203  func setsigstack(i uint32) {
   204  	throw("setsigstack")
   205  }
   206  
   207  //go:nosplit
   208  //go:nowritebarrierrec
   209  func getsig(i uint32) uintptr {
   210  	var sa sigactiont
   211  	sigaction(i, nil, &sa)
   212  	return sa.sa_sigaction
   213  }
   214  
   215  // setSignaltstackSP sets the ss_sp field of a stackt.
   216  //go:nosplit
   217  func setSignalstackSP(s *stackt, sp uintptr) {
   218  	s.ss_sp = sp
   219  }
   220  
   221  //go:nosplit
   222  //go:nowritebarrierrec
   223  func sigaddset(mask *sigset, i int) {
   224  	*mask |= 1 << (uint32(i) - 1)
   225  }
   226  
   227  func sigdelset(mask *sigset, i int) {
   228  	*mask &^= 1 << (uint32(i) - 1)
   229  }
   230  
   231  //go:nosplit
   232  func (c *sigctxt) fixsigcode(sig uint32) {
   233  }
   234  
   235  var haveMapStack = false
   236  
   237  func osStackAlloc(s *mspan) {
   238  	// OpenBSD 6.4+ requires that stacks be mapped with MAP_STACK.
   239  	// It will check this on entry to system calls, traps, and
   240  	// when switching to the alternate system stack.
   241  	//
   242  	// This function is called before s is used for any data, so
   243  	// it's safe to simply re-map it.
   244  	osStackRemap(s, _MAP_STACK)
   245  }
   246  
   247  func osStackFree(s *mspan) {
   248  	// Undo MAP_STACK.
   249  	osStackRemap(s, 0)
   250  }
   251  
   252  func osStackRemap(s *mspan, flags int32) {
   253  	if !haveMapStack {
   254  		// OpenBSD prior to 6.3 did not have MAP_STACK and so
   255  		// the following mmap will fail. But it also didn't
   256  		// require MAP_STACK (obviously), so there's no need
   257  		// to do the mmap.
   258  		return
   259  	}
   260  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   261  	if err != 0 || uintptr(a) != s.base() {
   262  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   263  		throw("remapping stack memory failed")
   264  	}
   265  }
   266  
   267  //go:nosplit
   268  func raise(sig uint32) {
   269  	thrkill(getthrid(), int(sig))
   270  }
   271  
   272  func signalM(mp *m, sig int) {
   273  	thrkill(int32(mp.procid), sig)
   274  }
   275  

View as plain text