github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/os1_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 "unsafe"
     8  
     9  const (
    10  	ESRCH       = 3
    11  	EAGAIN      = 35
    12  	EWOULDBLOCK = EAGAIN
    13  	ENOTSUP     = 91
    14  
    15  	// From OpenBSD's sys/time.h
    16  	CLOCK_REALTIME  = 0
    17  	CLOCK_VIRTUAL   = 1
    18  	CLOCK_PROF      = 2
    19  	CLOCK_MONOTONIC = 3
    20  )
    21  
    22  var sigset_none = uint32(0)
    23  var sigset_all = ^sigset_none
    24  
    25  // From OpenBSD's <sys/sysctl.h>
    26  const (
    27  	CTL_HW  = 6
    28  	HW_NCPU = 3
    29  )
    30  
    31  func getncpu() int32 {
    32  	mib := [2]uint32{CTL_HW, HW_NCPU}
    33  	out := uint32(0)
    34  	nout := unsafe.Sizeof(out)
    35  
    36  	// Fetch hw.ncpu via sysctl.
    37  	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    38  	if ret >= 0 {
    39  		return int32(out)
    40  	}
    41  	return 1
    42  }
    43  
    44  //go:nosplit
    45  func semacreate() uintptr {
    46  	return 1
    47  }
    48  
    49  //go:nosplit
    50  func semasleep(ns int64) int32 {
    51  	_g_ := getg()
    52  
    53  	// Compute sleep deadline.
    54  	var tsp *timespec
    55  	if ns >= 0 {
    56  		var ts timespec
    57  		var nsec int32
    58  		ns += nanotime()
    59  		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
    60  		ts.set_nsec(nsec)
    61  		tsp = &ts
    62  	}
    63  
    64  	for {
    65  		// spin-mutex lock
    66  		for {
    67  			if xchg(&_g_.m.waitsemalock, 1) == 0 {
    68  				break
    69  			}
    70  			osyield()
    71  		}
    72  
    73  		if _g_.m.waitsemacount != 0 {
    74  			// semaphore is available.
    75  			_g_.m.waitsemacount--
    76  			// spin-mutex unlock
    77  			atomicstore(&_g_.m.waitsemalock, 0)
    78  			return 0 // semaphore acquired
    79  		}
    80  
    81  		// sleep until semaphore != 0 or timeout.
    82  		// thrsleep unlocks m.waitsemalock.
    83  		ret := thrsleep((uintptr)(unsafe.Pointer(&_g_.m.waitsemacount)), CLOCK_MONOTONIC, tsp, (uintptr)(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount)))
    84  		if ret == EWOULDBLOCK {
    85  			return -1
    86  		}
    87  	}
    88  }
    89  
    90  //go:nosplit
    91  func semawakeup(mp *m) {
    92  	// spin-mutex lock
    93  	for {
    94  		if xchg(&mp.waitsemalock, 1) == 0 {
    95  			break
    96  		}
    97  		osyield()
    98  	}
    99  	mp.waitsemacount++
   100  	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
   101  	if ret != 0 && ret != ESRCH {
   102  		// semawakeup can be called on signal stack.
   103  		systemstack(func() {
   104  			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
   105  		})
   106  	}
   107  	// spin-mutex unlock
   108  	atomicstore(&mp.waitsemalock, 0)
   109  }
   110  
   111  func newosproc(mp *m, stk unsafe.Pointer) {
   112  	if false {
   113  		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
   114  	}
   115  
   116  	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
   117  
   118  	param := tforkt{
   119  		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
   120  		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
   121  		tf_stack: uintptr(stk),
   122  	}
   123  
   124  	oset := sigprocmask(_SIG_SETMASK, sigset_all)
   125  	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
   126  	sigprocmask(_SIG_SETMASK, oset)
   127  
   128  	if ret < 0 {
   129  		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
   130  		if ret == -ENOTSUP {
   131  			print("runtime: is kern.rthreads disabled?\n")
   132  		}
   133  		throw("runtime.newosproc")
   134  	}
   135  }
   136  
   137  func osinit() {
   138  	ncpu = getncpu()
   139  }
   140  
   141  var urandom_dev = []byte("/dev/urandom\x00")
   142  
   143  //go:nosplit
   144  func getRandomData(r []byte) {
   145  	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
   146  	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
   147  	close(fd)
   148  	extendRandom(r, int(n))
   149  }
   150  
   151  func goenvs() {
   152  	goenvs_unix()
   153  }
   154  
   155  // Called to initialize a new m (including the bootstrap m).
   156  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   157  func mpreinit(mp *m) {
   158  	mp.gsignal = malg(32 * 1024)
   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  	_g_ := getg()
   166  
   167  	// m.procid is a uint64, but tfork writes an int32. Fix it up.
   168  	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
   169  
   170  	// Initialize signal handling
   171  	signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024)
   172  	sigprocmask(_SIG_SETMASK, sigset_none)
   173  }
   174  
   175  // Called from dropm to undo the effect of an minit.
   176  func unminit() {
   177  	signalstack(nil, 0)
   178  }
   179  
   180  func memlimit() uintptr {
   181  	return 0
   182  }
   183  
   184  func sigtramp()
   185  
   186  type sigactiont struct {
   187  	sa_sigaction uintptr
   188  	sa_mask      uint32
   189  	sa_flags     int32
   190  }
   191  
   192  func setsig(i int32, fn uintptr, restart bool) {
   193  	var sa sigactiont
   194  	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
   195  	if restart {
   196  		sa.sa_flags |= _SA_RESTART
   197  	}
   198  	sa.sa_mask = sigset_all
   199  	if fn == funcPC(sighandler) {
   200  		fn = funcPC(sigtramp)
   201  	}
   202  	sa.sa_sigaction = fn
   203  	sigaction(i, &sa, nil)
   204  }
   205  
   206  func setsigstack(i int32) {
   207  	throw("setsigstack")
   208  }
   209  
   210  func getsig(i int32) uintptr {
   211  	var sa sigactiont
   212  	sigaction(i, nil, &sa)
   213  	if sa.sa_sigaction == funcPC(sigtramp) {
   214  		return funcPC(sighandler)
   215  	}
   216  	return sa.sa_sigaction
   217  }
   218  
   219  func signalstack(p *byte, n int32) {
   220  	var st stackt
   221  
   222  	st.ss_sp = uintptr(unsafe.Pointer(p))
   223  	st.ss_size = uintptr(n)
   224  	st.ss_flags = 0
   225  	if p == nil {
   226  		st.ss_flags = _SS_DISABLE
   227  	}
   228  	sigaltstack(&st, nil)
   229  }
   230  
   231  func unblocksignals() {
   232  	sigprocmask(_SIG_SETMASK, sigset_none)
   233  }