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 getCPUCount() 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  // mstart_stub provides glue code to call mstart from pthread_create.
   138  func mstart_stub()
   139  
   140  // May run with m.p==nil, so write barriers are not allowed.
   141  //
   142  //go:nowritebarrierrec
   143  func newosproc(mp *m) {
   144  	if false {
   145  		print("newosproc m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
   146  	}
   147  
   148  	// Initialize an attribute object.
   149  	var attr pthreadattr
   150  	if err := pthread_attr_init(&attr); err != 0 {
   151  		writeErrStr(failthreadcreate)
   152  		exit(1)
   153  	}
   154  
   155  	// Find out OS stack size for our own stack guard.
   156  	var stacksize uintptr
   157  	if pthread_attr_getstacksize(&attr, &stacksize) != 0 {
   158  		writeErrStr(failthreadcreate)
   159  		exit(1)
   160  	}
   161  	mp.g0.stack.hi = stacksize // for mstart
   162  
   163  	// Tell the pthread library we won't join with this thread.
   164  	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
   165  		writeErrStr(failthreadcreate)
   166  		exit(1)
   167  	}
   168  
   169  	// Finally, create the thread. It starts at mstart_stub, which does some low-level
   170  	// setup and then calls mstart.
   171  	var oset sigset
   172  	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
   173  	err := retryOnEAGAIN(func() int32 {
   174  		return pthread_create(&attr, abi.FuncPCABI0(mstart_stub), unsafe.Pointer(mp))
   175  	})
   176  	sigprocmask(_SIG_SETMASK, &oset, nil)
   177  	if err != 0 {
   178  		writeErrStr(failthreadcreate)
   179  		exit(1)
   180  	}
   181  
   182  	pthread_attr_destroy(&attr)
   183  }
   184  
   185  func osinit() {
   186  	numCPUStartup = getCPUCount()
   187  	physPageSize = getPageSize()
   188  }
   189  
   190  // TODO(#69781): set startupRand using the .openbsd.randomdata ELF section.
   191  // See SPECS.randomdata.
   192  
   193  var urandom_dev = []byte("/dev/urandom\x00")
   194  
   195  //go:nosplit
   196  func readRandom(r []byte) int {
   197  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   198  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   199  	closefd(fd)
   200  	return int(n)
   201  }
   202  
   203  func goenvs() {
   204  	goenvs_unix()
   205  }
   206  
   207  // Called to initialize a new m (including the bootstrap m).
   208  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   209  func mpreinit(mp *m) {
   210  	gsignalSize := int32(32 * 1024)
   211  	mp.gsignal = malg(gsignalSize)
   212  	mp.gsignal.m = mp
   213  }
   214  
   215  // Called to initialize a new m (including the bootstrap m).
   216  // Called on the new thread, can not allocate memory.
   217  func minit() {
   218  	getg().m.procid = uint64(getthrid())
   219  	minitSignals()
   220  }
   221  
   222  // Called from dropm to undo the effect of an minit.
   223  //
   224  //go:nosplit
   225  func unminit() {
   226  	unminitSignals()
   227  	getg().m.procid = 0
   228  }
   229  
   230  // Called from mexit, but not from dropm, to undo the effect of thread-owned
   231  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   232  //
   233  // This always runs without a P, so //go:nowritebarrierrec is required.
   234  //
   235  //go:nowritebarrierrec
   236  func mdestroy(mp *m) {
   237  }
   238  
   239  func sigtramp()
   240  
   241  type sigactiont struct {
   242  	sa_sigaction uintptr
   243  	sa_mask      uint32
   244  	sa_flags     int32
   245  }
   246  
   247  //go:nosplit
   248  //go:nowritebarrierrec
   249  func setsig(i uint32, fn uintptr) {
   250  	var sa sigactiont
   251  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
   252  	sa.sa_mask = uint32(sigset_all)
   253  	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
   254  		fn = abi.FuncPCABI0(sigtramp)
   255  	}
   256  	sa.sa_sigaction = fn
   257  	sigaction(i, &sa, nil)
   258  }
   259  
   260  //go:nosplit
   261  //go:nowritebarrierrec
   262  func setsigstack(i uint32) {
   263  	throw("setsigstack")
   264  }
   265  
   266  //go:nosplit
   267  //go:nowritebarrierrec
   268  func getsig(i uint32) uintptr {
   269  	var sa sigactiont
   270  	sigaction(i, nil, &sa)
   271  	return sa.sa_sigaction
   272  }
   273  
   274  // setSignalstackSP sets the ss_sp field of a stackt.
   275  //
   276  //go:nosplit
   277  func setSignalstackSP(s *stackt, sp uintptr) {
   278  	s.ss_sp = sp
   279  }
   280  
   281  //go:nosplit
   282  //go:nowritebarrierrec
   283  func sigaddset(mask *sigset, i int) {
   284  	*mask |= 1 << (uint32(i) - 1)
   285  }
   286  
   287  func sigdelset(mask *sigset, i int) {
   288  	*mask &^= 1 << (uint32(i) - 1)
   289  }
   290  
   291  //go:nosplit
   292  func (c *sigctxt) fixsigcode(sig uint32) {
   293  }
   294  
   295  func setProcessCPUProfiler(hz int32) {
   296  	setProcessCPUProfilerTimer(hz)
   297  }
   298  
   299  func setThreadCPUProfiler(hz int32) {
   300  	setThreadCPUProfilerHz(hz)
   301  }
   302  
   303  //go:nosplit
   304  func validSIGPROF(mp *m, c *sigctxt) bool {
   305  	return true
   306  }
   307  
   308  func osStackAlloc(s *mspan) {
   309  	osStackRemap(s, _MAP_STACK)
   310  }
   311  
   312  func osStackFree(s *mspan) {
   313  	// Undo MAP_STACK.
   314  	osStackRemap(s, 0)
   315  }
   316  
   317  func osStackRemap(s *mspan, flags int32) {
   318  	a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0)
   319  	if err != 0 || uintptr(a) != s.base() {
   320  		print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n")
   321  		throw("remapping stack memory failed")
   322  	}
   323  }
   324  
   325  //go:nosplit
   326  func raise(sig uint32) {
   327  	thrkill(getthrid(), int(sig))
   328  }
   329  
   330  func signalM(mp *m, sig int) {
   331  	thrkill(int32(mp.procid), sig)
   332  }
   333  
   334  // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
   335  // number.
   336  const sigPerThreadSyscall = 1 << 31
   337  
   338  //go:nosplit
   339  func runPerThreadSyscall() {
   340  	throw("runPerThreadSyscall only valid on linux")
   341  }
   342  

View as plain text