Source file src/runtime/os_openbsd.go

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

View as plain text