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  var urandom_dev = []byte("/dev/urandom\x00")
   143  
   144  //go:nosplit
   145  func readRandom(r []byte) int {
   146  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   147  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   148  	closefd(fd)
   149  	return int(n)
   150  }
   151  
   152  func goenvs() {
   153  	goenvs_unix()
   154  }
   155  
   156  // Called to initialize a new m (including the bootstrap m).
   157  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   158  func mpreinit(mp *m) {
   159  	gsignalSize := int32(32 * 1024)
   160  	if GOARCH == "mips64" {
   161  		gsignalSize = int32(64 * 1024)
   162  	}
   163  	mp.gsignal = malg(gsignalSize)
   164  	mp.gsignal.m = mp
   165  }
   166  
   167  // Called to initialize a new m (including the bootstrap m).
   168  // Called on the new thread, can not allocate memory.
   169  func minit() {
   170  	getg().m.procid = uint64(getthrid())
   171  	minitSignals()
   172  }
   173  
   174  // Called from dropm to undo the effect of an minit.
   175  //
   176  //go:nosplit
   177  func unminit() {
   178  	unminitSignals()
   179  	getg().m.procid = 0
   180  }
   181  
   182  // Called from exitm, but not from drop, to undo the effect of thread-owned
   183  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   184  func mdestroy(mp *m) {
   185  }
   186  
   187  func sigtramp()
   188  
   189  type sigactiont struct {
   190  	sa_sigaction uintptr
   191  	sa_mask      uint32
   192  	sa_flags     int32
   193  }
   194  
   195  //go:nosplit
   196  //go:nowritebarrierrec
   197  func setsig(i uint32, fn uintptr) {
   198  	var sa sigactiont
   199  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   200  	sa.sa_mask = uint32(sigset_all)
   201  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   202  		fn = abi.FuncPCABI0(sigtramp)
   203  	}
   204  	sa.sa_sigaction = fn
   205  	sigaction(i, &sa, nil)
   206  }
   207  
   208  //go:nosplit
   209  //go:nowritebarrierrec
   210  func setsigstack(i uint32) {
   211  	throw("setsigstack")
   212  }
   213  
   214  //go:nosplit
   215  //go:nowritebarrierrec
   216  func getsig(i uint32) uintptr {
   217  	var sa sigactiont
   218  	sigaction(i, nil, &sa)
   219  	return sa.sa_sigaction
   220  }
   221  
   222  // setSignalstackSP sets the ss_sp field of a stackt.
   223  //
   224  //go:nosplit
   225  func setSignalstackSP(s *stackt, sp uintptr) {
   226  	s.ss_sp = sp
   227  }
   228  
   229  //go:nosplit
   230  //go:nowritebarrierrec
   231  func sigaddset(mask *sigset, i int) {
   232  	*mask |= 1 << (uint32(i) - 1)
   233  }
   234  
   235  func sigdelset(mask *sigset, i int) {
   236  	*mask &^= 1 << (uint32(i) - 1)
   237  }
   238  
   239  //go:nosplit
   240  func (c *sigctxt) fixsigcode(sig uint32) {
   241  }
   242  
   243  func setProcessCPUProfiler(hz int32) {
   244  	setProcessCPUProfilerTimer(hz)
   245  }
   246  
   247  func setThreadCPUProfiler(hz int32) {
   248  	setThreadCPUProfilerHz(hz)
   249  }
   250  
   251  //go:nosplit
   252  func validSIGPROF(mp *m, c *sigctxt) bool {
   253  	return true
   254  }
   255  
   256  func osStackAlloc(s *mspan) {
   257  	osStackRemap(s, _MAP_STACK)
   258  }
   259  
   260  func osStackFree(s *mspan) {
   261  	// Undo MAP_STACK.
   262  	osStackRemap(s, 0)
   263  }
   264  
   265  func osStackRemap(s *mspan, flags int32) {
   266  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   267  	if err != 0 || uintptr(a) != s.base() {
   268  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   269  		throw("remapping stack memory failed")
   270  	}
   271  }
   272  
   273  //go:nosplit
   274  func raise(sig uint32) {
   275  	thrkill(getthrid(), int(sig))
   276  }
   277  
   278  func signalM(mp *m, sig int) {
   279  	thrkill(int32(mp.procid), sig)
   280  }
   281  
   282  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   283  // number.
   284  const sigPerThreadSyscall = 1 << 31
   285  
   286  //go:nosplit
   287  func runPerThreadSyscall() {
   288  	throw("runPerThreadSyscall only valid on linux")
   289  }
   290  

View as plain text