Home | History | Annotate | Download | only in 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 //go:noescape
     17 func setitimer(mode int32, new, old *itimerval)
     18 
     19 //go:noescape
     20 func sigaction(sig uint32, new, old *sigactiont)
     21 
     22 //go:noescape
     23 func sigaltstack(new, old *stackt)
     24 
     25 //go:noescape
     26 func obsdsigprocmask(how int32, new sigset) sigset
     27 
     28 //go:nosplit
     29 //go:nowritebarrierrec
     30 func sigprocmask(how int32, new, old *sigset) {
     31 	n := sigset(0)
     32 	if new != nil {
     33 		n = *new
     34 	}
     35 	r := obsdsigprocmask(how, n)
     36 	if old != nil {
     37 		*old = r
     38 	}
     39 }
     40 
     41 //go:noescape
     42 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
     43 
     44 func raise(sig uint32)
     45 func raiseproc(sig uint32)
     46 
     47 //go:noescape
     48 func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
     49 
     50 //go:noescape
     51 func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
     52 
     53 //go:noescape
     54 func thrwakeup(ident uintptr, n int32) int32
     55 
     56 func osyield()
     57 
     58 const (
     59 	_ESRCH       = 3
     60 	_EAGAIN      = 35
     61 	_EWOULDBLOCK = _EAGAIN
     62 	_ENOTSUP     = 91
     63 
     64 	// From OpenBSD's sys/time.h
     65 	_CLOCK_REALTIME  = 0
     66 	_CLOCK_VIRTUAL   = 1
     67 	_CLOCK_PROF      = 2
     68 	_CLOCK_MONOTONIC = 3
     69 )
     70 
     71 type sigset uint32
     72 
     73 var sigset_all = ^sigset(0)
     74 
     75 // From OpenBSD's <sys/sysctl.h>
     76 const (
     77 	_CTL_HW      = 6
     78 	_HW_NCPU     = 3
     79 	_HW_PAGESIZE = 7
     80 )
     81 
     82 func getncpu() int32 {
     83 	mib := [2]uint32{_CTL_HW, _HW_NCPU}
     84 	out := uint32(0)
     85 	nout := unsafe.Sizeof(out)
     86 
     87 	// Fetch hw.ncpu via sysctl.
     88 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     89 	if ret >= 0 {
     90 		return int32(out)
     91 	}
     92 	return 1
     93 }
     94 
     95 func getPageSize() uintptr {
     96 	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
     97 	out := uint32(0)
     98 	nout := unsafe.Sizeof(out)
     99 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    100 	if ret >= 0 {
    101 		return uintptr(out)
    102 	}
    103 	return 0
    104 }
    105 
    106 //go:nosplit
    107 func semacreate(mp *m) {
    108 }
    109 
    110 //go:nosplit
    111 func semasleep(ns int64) int32 {
    112 	_g_ := getg()
    113 
    114 	// Compute sleep deadline.
    115 	var tsp *timespec
    116 	if ns >= 0 {
    117 		var ts timespec
    118 		var nsec int32
    119 		ns += nanotime()
    120 		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
    121 		ts.set_nsec(nsec)
    122 		tsp = &ts
    123 	}
    124 
    125 	for {
    126 		v := atomic.Load(&_g_.m.waitsemacount)
    127 		if v > 0 {
    128 			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
    129 				return 0 // semaphore acquired
    130 			}
    131 			continue
    132 		}
    133 
    134 		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
    135 		//
    136 		// From OpenBSD's __thrsleep(2) manual:
    137 		// "The abort argument, if not NULL, points to an int that will
    138 		// be examined [...] immediately before blocking. If that int
    139 		// is non-zero then __thrsleep() will immediately return EINTR
    140 		// without blocking."
    141 		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
    142 		if ret == _EWOULDBLOCK {
    143 			return -1
    144 		}
    145 	}
    146 }
    147 
    148 //go:nosplit
    149 func semawakeup(mp *m) {
    150 	atomic.Xadd(&mp.waitsemacount, 1)
    151 	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
    152 	if ret != 0 && ret != _ESRCH {
    153 		// semawakeup can be called on signal stack.
    154 		systemstack(func() {
    155 			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
    156 		})
    157 	}
    158 }
    159 
    160 // May run with m.p==nil, so write barriers are not allowed.
    161 //go:nowritebarrier
    162 func newosproc(mp *m, stk unsafe.Pointer) {
    163 	if false {
    164 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
    165 	}
    166 
    167 	param := tforkt{
    168 		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
    169 		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
    170 		tf_stack: uintptr(stk),
    171 	}
    172 
    173 	var oset sigset
    174 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    175 	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
    176 	sigprocmask(_SIG_SETMASK, &oset, nil)
    177 
    178 	if ret < 0 {
    179 		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
    180 		if ret == -_EAGAIN {
    181 			println("runtime: may need to increase max user processes (ulimit -p)")
    182 		}
    183 		throw("runtime.newosproc")
    184 	}
    185 }
    186 
    187 func osinit() {
    188 	ncpu = getncpu()
    189 	physPageSize = getPageSize()
    190 }
    191 
    192 var urandom_dev = []byte("/dev/urandom\x00")
    193 
    194 //go:nosplit
    195 func getRandomData(r []byte) {
    196 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    197 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    198 	closefd(fd)
    199 	extendRandom(r, int(n))
    200 }
    201 
    202 func goenvs() {
    203 	goenvs_unix()
    204 }
    205 
    206 // Called to initialize a new m (including the bootstrap m).
    207 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    208 func mpreinit(mp *m) {
    209 	mp.gsignal = malg(32 * 1024)
    210 	mp.gsignal.m = mp
    211 }
    212 
    213 // Called to initialize a new m (including the bootstrap m).
    214 // Called on the new thread, can not allocate memory.
    215 func minit() {
    216 	// m.procid is a uint64, but tfork writes an int32. Fix it up.
    217 	_g_ := getg()
    218 	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
    219 
    220 	minitSignals()
    221 }
    222 
    223 // Called from dropm to undo the effect of an minit.
    224 //go:nosplit
    225 func unminit() {
    226 	unminitSignals()
    227 }
    228 
    229 func memlimit() uintptr {
    230 	return 0
    231 }
    232 
    233 func sigtramp()
    234 
    235 type sigactiont struct {
    236 	sa_sigaction uintptr
    237 	sa_mask      uint32
    238 	sa_flags     int32
    239 }
    240 
    241 //go:nosplit
    242 //go:nowritebarrierrec
    243 func setsig(i uint32, fn uintptr) {
    244 	var sa sigactiont
    245 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
    246 	sa.sa_mask = uint32(sigset_all)
    247 	if fn == funcPC(sighandler) {
    248 		fn = funcPC(sigtramp)
    249 	}
    250 	sa.sa_sigaction = fn
    251 	sigaction(i, &sa, nil)
    252 }
    253 
    254 //go:nosplit
    255 //go:nowritebarrierrec
    256 func setsigstack(i uint32) {
    257 	throw("setsigstack")
    258 }
    259 
    260 //go:nosplit
    261 //go:nowritebarrierrec
    262 func getsig(i uint32) uintptr {
    263 	var sa sigactiont
    264 	sigaction(i, nil, &sa)
    265 	return sa.sa_sigaction
    266 }
    267 
    268 // setSignaltstackSP sets the ss_sp field of a stackt.
    269 //go:nosplit
    270 func setSignalstackSP(s *stackt, sp uintptr) {
    271 	s.ss_sp = sp
    272 }
    273 
    274 //go:nosplit
    275 //go:nowritebarrierrec
    276 func sigaddset(mask *sigset, i int) {
    277 	*mask |= 1 << (uint32(i) - 1)
    278 }
    279 
    280 func sigdelset(mask *sigset, i int) {
    281 	*mask &^= 1 << (uint32(i) - 1)
    282 }
    283 
    284 func (c *sigctxt) fixsigcode(sig uint32) {
    285 }
    286