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  //go:nosplit
   172  func unminit() {
   173  	unminitSignals()
   174  }
   175  
   176  // Called from exitm, but not from drop, to undo the effect of thread-owned
   177  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   178  func mdestroy(mp *m) {
   179  }
   180  
   181  func sigtramp()
   182  
   183  type sigactiont struct {
   184  	sa_sigaction uintptr
   185  	sa_mask      uint32
   186  	sa_flags     int32
   187  }
   188  
   189  //go:nosplit
   190  //go:nowritebarrierrec
   191  func setsig(i uint32, fn uintptr) {
   192  	var sa sigactiont
   193  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   194  	sa.sa_mask = uint32(sigset_all)
   195  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   196  		fn = abi.FuncPCABI0(sigtramp)
   197  	}
   198  	sa.sa_sigaction = fn
   199  	sigaction(i, &sa, nil)
   200  }
   201  
   202  //go:nosplit
   203  //go:nowritebarrierrec
   204  func setsigstack(i uint32) {
   205  	throw("setsigstack")
   206  }
   207  
   208  //go:nosplit
   209  //go:nowritebarrierrec
   210  func getsig(i uint32) uintptr {
   211  	var sa sigactiont
   212  	sigaction(i, nil, &sa)
   213  	return sa.sa_sigaction
   214  }
   215  
   216  // setSignaltstackSP sets the ss_sp field of a stackt.
   217  //go:nosplit
   218  func setSignalstackSP(s *stackt, sp uintptr) {
   219  	s.ss_sp = sp
   220  }
   221  
   222  //go:nosplit
   223  //go:nowritebarrierrec
   224  func sigaddset(mask *sigset, i int) {
   225  	*mask |= 1 << (uint32(i) - 1)
   226  }
   227  
   228  func sigdelset(mask *sigset, i int) {
   229  	*mask &^= 1 << (uint32(i) - 1)
   230  }
   231  
   232  //go:nosplit
   233  func (c *sigctxt) fixsigcode(sig uint32) {
   234  }
   235  
   236  func setProcessCPUProfiler(hz int32) {
   237  	setProcessCPUProfilerTimer(hz)
   238  }
   239  
   240  func setThreadCPUProfiler(hz int32) {
   241  	setThreadCPUProfilerHz(hz)
   242  }
   243  
   244  //go:nosplit
   245  func validSIGPROF(mp *m, c *sigctxt) bool {
   246  	return true
   247  }
   248  
   249  var haveMapStack = false
   250  
   251  func osStackAlloc(s *mspan) {
   252  	// OpenBSD 6.4+ requires that stacks be mapped with MAP_STACK.
   253  	// It will check this on entry to system calls, traps, and
   254  	// when switching to the alternate system stack.
   255  	//
   256  	// This function is called before s is used for any data, so
   257  	// it's safe to simply re-map it.
   258  	osStackRemap(s, _MAP_STACK)
   259  }
   260  
   261  func osStackFree(s *mspan) {
   262  	// Undo MAP_STACK.
   263  	osStackRemap(s, 0)
   264  }
   265  
   266  func osStackRemap(s *mspan, flags int32) {
   267  	if !haveMapStack {
   268  		// OpenBSD prior to 6.3 did not have MAP_STACK and so
   269  		// the following mmap will fail. But it also didn't
   270  		// require MAP_STACK (obviously), so there's no need
   271  		// to do the mmap.
   272  		return
   273  	}
   274  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   275  	if err != 0 || uintptr(a) != s.base() {
   276  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   277  		throw("remapping stack memory failed")
   278  	}
   279  }
   280  
   281  //go:nosplit
   282  func raise(sig uint32) {
   283  	thrkill(getthrid(), int(sig))
   284  }
   285  
   286  func signalM(mp *m, sig int) {
   287  	thrkill(int32(mp.procid), sig)
   288  }
   289  
   290  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   291  // number.
   292  const sigPerThreadSyscall = 1 << 31
   293  
   294  //go:nosplit
   295  func runPerThreadSyscall() {
   296  	throw("runPerThreadSyscall only valid on linux")
   297  }
   298  

View as plain text