...

Source file src/runtime/os_openbsd.go

Documentation: runtime

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

View as plain text