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