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 // From FreeBSD's <sys/sysctl.h>
     10 const (
     11 	_CTL_HW  = 6
     12 	_HW_NCPU = 3
     13 )
     14 
     15 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
     16 
     17 func getncpu() int32 {
     18 	mib := [2]uint32{_CTL_HW, _HW_NCPU}
     19 	out := uint32(0)
     20 	nout := unsafe.Sizeof(out)
     21 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     22 	if ret >= 0 {
     23 		return int32(out)
     24 	}
     25 	return 1
     26 }
     27 
     28 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
     29 // thus the code is largely similar. See Linux implementation
     30 // and lock_futex.go for comments.
     31 
     32 //go:nosplit
     33 func futexsleep(addr *uint32, val uint32, ns int64) {
     34 	systemstack(func() {
     35 		futexsleep1(addr, val, ns)
     36 	})
     37 }
     38 
     39 func futexsleep1(addr *uint32, val uint32, ns int64) {
     40 	var tsp *timespec
     41 	if ns >= 0 {
     42 		var ts timespec
     43 		ts.tv_nsec = 0
     44 		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
     45 		tsp = &ts
     46 	}
     47 	ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
     48 	if ret >= 0 || ret == -_EINTR {
     49 		return
     50 	}
     51 	print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
     52 	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
     53 }
     54 
     55 //go:nosplit
     56 func futexwakeup(addr *uint32, cnt uint32) {
     57 	ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
     58 	if ret >= 0 {
     59 		return
     60 	}
     61 
     62 	systemstack(func() {
     63 		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
     64 	})
     65 }
     66 
     67 func thr_start()
     68 
     69 // May run with m.p==nil, so write barriers are not allowed.
     70 //go:nowritebarrier
     71 func newosproc(mp *m, stk unsafe.Pointer) {
     72 	if false {
     73 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
     74 	}
     75 
     76 	// NOTE(rsc): This code is confused. stackbase is the top of the stack
     77 	// and is equal to stk. However, it's working, so I'm not changing it.
     78 	param := thrparam{
     79 		start_func: funcPC(thr_start),
     80 		arg:        unsafe.Pointer(mp),
     81 		stack_base: mp.g0.stack.hi,
     82 		stack_size: uintptr(stk) - mp.g0.stack.hi,
     83 		child_tid:  unsafe.Pointer(&mp.procid),
     84 		parent_tid: nil,
     85 		tls_base:   unsafe.Pointer(&mp.tls[0]),
     86 		tls_size:   unsafe.Sizeof(mp.tls),
     87 	}
     88 	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
     89 
     90 	var oset sigset
     91 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
     92 	thr_new(&param, int32(unsafe.Sizeof(param)))
     93 	sigprocmask(_SIG_SETMASK, &oset, nil)
     94 }
     95 
     96 func osinit() {
     97 	ncpu = getncpu()
     98 }
     99 
    100 var urandom_dev = []byte("/dev/urandom\x00")
    101 
    102 //go:nosplit
    103 func getRandomData(r []byte) {
    104 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    105 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    106 	closefd(fd)
    107 	extendRandom(r, int(n))
    108 }
    109 
    110 func goenvs() {
    111 	goenvs_unix()
    112 }
    113 
    114 // Called to initialize a new m (including the bootstrap m).
    115 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    116 func mpreinit(mp *m) {
    117 	mp.gsignal = malg(32 * 1024)
    118 	mp.gsignal.m = mp
    119 }
    120 
    121 func msigsave(mp *m) {
    122 	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
    123 	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
    124 		throw("insufficient storage for signal mask")
    125 	}
    126 	sigprocmask(_SIG_SETMASK, nil, smask)
    127 }
    128 
    129 // Called to initialize a new m (including the bootstrap m).
    130 // Called on the new thread, can not allocate memory.
    131 func minit() {
    132 	_g_ := getg()
    133 
    134 	// m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
    135 	// Fix it up. (Only matters on big-endian, but be clean anyway.)
    136 	if ptrSize == 4 {
    137 		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
    138 	}
    139 
    140 	// Initialize signal handling.
    141 	signalstack(&_g_.m.gsignal.stack)
    142 
    143 	// restore signal mask from m.sigmask and unblock essential signals
    144 	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
    145 	for i := range sigtable {
    146 		if sigtable[i].flags&_SigUnblock != 0 {
    147 			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
    148 		}
    149 	}
    150 	sigprocmask(_SIG_SETMASK, &nmask, nil)
    151 }
    152 
    153 // Called from dropm to undo the effect of an minit.
    154 func unminit() {
    155 	_g_ := getg()
    156 	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
    157 	sigprocmask(_SIG_SETMASK, smask, nil)
    158 	signalstack(nil)
    159 }
    160 
    161 func memlimit() uintptr {
    162 	/*
    163 		TODO: Convert to Go when something actually uses the result.
    164 		Rlimit rl;
    165 		extern byte runtimetext[], runtimeend[];
    166 		uintptr used;
    167 
    168 		if(runtimegetrlimit(RLIMIT_AS, &rl) != 0)
    169 			return 0;
    170 		if(rl.rlim_cur >= 0x7fffffff)
    171 			return 0;
    172 
    173 		// Estimate our VM footprint excluding the heap.
    174 		// Not an exact science: use size of binary plus
    175 		// some room for thread stacks.
    176 		used = runtimeend - runtimetext + (64<<20);
    177 		if(used >= rl.rlim_cur)
    178 			return 0;
    179 
    180 		// If there's not at least 16 MB left, we're probably
    181 		// not going to be able to do much.  Treat as no limit.
    182 		rl.rlim_cur -= used;
    183 		if(rl.rlim_cur < (16<<20))
    184 			return 0;
    185 
    186 		return rl.rlim_cur - used;
    187 	*/
    188 
    189 	return 0
    190 }
    191 
    192 func sigtramp()
    193 
    194 type sigactiont struct {
    195 	sa_handler uintptr
    196 	sa_flags   int32
    197 	sa_mask    sigset
    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_handler = 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_handler == funcPC(sigtramp) {
    222 		return funcPC(sighandler)
    223 	}
    224 	return sa.sa_handler
    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 [(_NSIG + 31) / 32]uint32) {
    240 	var mask sigset
    241 	copy(mask.__bits[:], m[:])
    242 	sigprocmask(_SIG_SETMASK, &mask, nil)
    243 }
    244 
    245 func unblocksig(sig int32) {
    246 	var mask sigset
    247 	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
    248 	sigprocmask(_SIG_UNBLOCK, &mask, nil)
    249 }
    250