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

View as plain text