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 "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 const (
     23 	sigset_none = uint32(0)
     24 	sigset_all  = ^uint32(0)
     25 )
     26 
     27 // From OpenBSD's <sys/sysctl.h>
     28 const (
     29 	_CTL_HW  = 6
     30 	_HW_NCPU = 3
     31 )
     32 
     33 func getncpu() int32 {
     34 	mib := [2]uint32{_CTL_HW, _HW_NCPU}
     35 	out := uint32(0)
     36 	nout := unsafe.Sizeof(out)
     37 
     38 	// Fetch hw.ncpu via sysctl.
     39 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     40 	if ret >= 0 {
     41 		return int32(out)
     42 	}
     43 	return 1
     44 }
     45 
     46 //go:nosplit
     47 func semacreate() uintptr {
     48 	return 1
     49 }
     50 
     51 //go:nosplit
     52 func semasleep(ns int64) int32 {
     53 	_g_ := getg()
     54 
     55 	// Compute sleep deadline.
     56 	var tsp *timespec
     57 	if ns >= 0 {
     58 		var ts timespec
     59 		var nsec int32
     60 		ns += nanotime()
     61 		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
     62 		ts.set_nsec(nsec)
     63 		tsp = &ts
     64 	}
     65 
     66 	for {
     67 		v := atomicload(&_g_.m.waitsemacount)
     68 		if v > 0 {
     69 			if cas(&_g_.m.waitsemacount, v, v-1) {
     70 				return 0 // semaphore acquired
     71 			}
     72 			continue
     73 		}
     74 
     75 		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
     76 		//
     77 		// From OpenBSD's __thrsleep(2) manual:
     78 		// "The abort argument, if not NULL, points to an int that will
     79 		// be examined [...] immediately before blocking.  If that int
     80 		// is non-zero then __thrsleep() will immediately return EINTR
     81 		// without blocking."
     82 		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
     83 		if ret == _EWOULDBLOCK {
     84 			return -1
     85 		}
     86 	}
     87 }
     88 
     89 //go:nosplit
     90 func semawakeup(mp *m) {
     91 	xadd(&mp.waitsemacount, 1)
     92 	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
     93 	if ret != 0 && ret != _ESRCH {
     94 		// semawakeup can be called on signal stack.
     95 		systemstack(func() {
     96 			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
     97 		})
     98 	}
     99 }
    100 
    101 // May run with m.p==nil, so write barriers are not allowed.
    102 //go:nowritebarrier
    103 func newosproc(mp *m, stk unsafe.Pointer) {
    104 	if false {
    105 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
    106 	}
    107 
    108 	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
    109 
    110 	param := tforkt{
    111 		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
    112 		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
    113 		tf_stack: uintptr(stk),
    114 	}
    115 
    116 	oset := sigprocmask(_SIG_SETMASK, sigset_all)
    117 	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
    118 	sigprocmask(_SIG_SETMASK, oset)
    119 
    120 	if ret < 0 {
    121 		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
    122 		throw("runtime.newosproc")
    123 	}
    124 }
    125 
    126 func osinit() {
    127 	ncpu = getncpu()
    128 }
    129 
    130 var urandom_dev = []byte("/dev/urandom\x00")
    131 
    132 //go:nosplit
    133 func getRandomData(r []byte) {
    134 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    135 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    136 	closefd(fd)
    137 	extendRandom(r, int(n))
    138 }
    139 
    140 func goenvs() {
    141 	goenvs_unix()
    142 }
    143 
    144 // Called to initialize a new m (including the bootstrap m).
    145 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    146 func mpreinit(mp *m) {
    147 	mp.gsignal = malg(32 * 1024)
    148 	mp.gsignal.m = mp
    149 }
    150 
    151 func msigsave(mp *m) {
    152 	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
    153 	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
    154 		throw("insufficient storage for signal mask")
    155 	}
    156 	*smask = sigprocmask(_SIG_BLOCK, 0)
    157 }
    158 
    159 // Called to initialize a new m (including the bootstrap m).
    160 // Called on the new thread, can not allocate memory.
    161 func minit() {
    162 	_g_ := getg()
    163 
    164 	// m.procid is a uint64, but tfork writes an int32. Fix it up.
    165 	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
    166 
    167 	// Initialize signal handling
    168 	signalstack(&_g_.m.gsignal.stack)
    169 
    170 	// restore signal mask from m.sigmask and unblock essential signals
    171 	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
    172 	for i := range sigtable {
    173 		if sigtable[i].flags&_SigUnblock != 0 {
    174 			nmask &^= 1 << (uint32(i) - 1)
    175 		}
    176 	}
    177 	sigprocmask(_SIG_SETMASK, nmask)
    178 }
    179 
    180 // Called from dropm to undo the effect of an minit.
    181 func unminit() {
    182 	_g_ := getg()
    183 	smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
    184 	sigprocmask(_SIG_SETMASK, smask)
    185 	signalstack(nil)
    186 }
    187 
    188 func memlimit() uintptr {
    189 	return 0
    190 }
    191 
    192 func sigtramp()
    193 
    194 type sigactiont struct {
    195 	sa_sigaction uintptr
    196 	sa_mask      uint32
    197 	sa_flags     int32
    198 }
    199 
    200 func setsig(i int32, fn uintptr, restart bool) {
    201 	var sa sigactiont
    202 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
    203 	if restart {
    204 		sa.sa_flags |= _SA_RESTART
    205 	}
    206 	sa.sa_mask = sigset_all
    207 	if fn == funcPC(sighandler) {
    208 		fn = funcPC(sigtramp)
    209 	}
    210 	sa.sa_sigaction = fn
    211 	sigaction(i, &sa, nil)
    212 }
    213 
    214 func setsigstack(i int32) {
    215 	throw("setsigstack")
    216 }
    217 
    218 func getsig(i int32) uintptr {
    219 	var sa sigactiont
    220 	sigaction(i, nil, &sa)
    221 	if sa.sa_sigaction == funcPC(sigtramp) {
    222 		return funcPC(sighandler)
    223 	}
    224 	return sa.sa_sigaction
    225 }
    226 
    227 func signalstack(s *stack) {
    228 	var st stackt
    229 	if s == nil {
    230 		st.ss_flags = _SS_DISABLE
    231 	} else {
    232 		st.ss_sp = s.lo
    233 		st.ss_size = s.hi - s.lo
    234 		st.ss_flags = 0
    235 	}
    236 	sigaltstack(&st, nil)
    237 }
    238 
    239 func updatesigmask(m sigmask) {
    240 	sigprocmask(_SIG_SETMASK, m[0])
    241 }
    242 
    243 func unblocksig(sig int32) {
    244 	mask := uint32(1) << (uint32(sig) - 1)
    245 	sigprocmask(_SIG_UNBLOCK, mask)
    246 }
    247