Home | History | Annotate | Download | only in runtime
      1 // Copyright 2014 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 	_NSIG        = 33
     11 	_SI_USER     = 0
     12 	_SS_DISABLE  = 4
     13 	_RLIMIT_AS   = 10
     14 	_SIG_BLOCK   = 1
     15 	_SIG_UNBLOCK = 2
     16 	_SIG_SETMASK = 3
     17 )
     18 
     19 type mOS struct{}
     20 
     21 //go:noescape
     22 func lwp_create(param *lwpparams) int32
     23 
     24 //go:noescape
     25 func sigaltstack(new, old *stackt)
     26 
     27 //go:noescape
     28 func sigaction(sig uint32, new, old *sigactiont)
     29 
     30 //go:noescape
     31 func sigprocmask(how int32, new, old *sigset)
     32 
     33 //go:noescape
     34 func setitimer(mode int32, new, old *itimerval)
     35 
     36 //go:noescape
     37 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
     38 
     39 //go:noescape
     40 func getrlimit(kind int32, limit unsafe.Pointer) int32
     41 
     42 func raise(sig uint32)
     43 func raiseproc(sig uint32)
     44 
     45 //go:noescape
     46 func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
     47 
     48 //go:noescape
     49 func sys_umtx_wakeup(addr *uint32, val int32) int32
     50 
     51 func osyield()
     52 
     53 const stackSystem = 0
     54 
     55 // From DragonFly's <sys/sysctl.h>
     56 const (
     57 	_CTL_HW      = 6
     58 	_HW_NCPU     = 3
     59 	_HW_PAGESIZE = 7
     60 )
     61 
     62 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
     63 
     64 func getncpu() int32 {
     65 	mib := [2]uint32{_CTL_HW, _HW_NCPU}
     66 	out := uint32(0)
     67 	nout := unsafe.Sizeof(out)
     68 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     69 	if ret >= 0 {
     70 		return int32(out)
     71 	}
     72 	return 1
     73 }
     74 
     75 func getPageSize() uintptr {
     76 	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
     77 	out := uint32(0)
     78 	nout := unsafe.Sizeof(out)
     79 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     80 	if ret >= 0 {
     81 		return uintptr(out)
     82 	}
     83 	return 0
     84 }
     85 
     86 //go:nosplit
     87 func futexsleep(addr *uint32, val uint32, ns int64) {
     88 	systemstack(func() {
     89 		futexsleep1(addr, val, ns)
     90 	})
     91 }
     92 
     93 func futexsleep1(addr *uint32, val uint32, ns int64) {
     94 	var timeout int32
     95 	if ns >= 0 {
     96 		// The timeout is specified in microseconds - ensure that we
     97 		// do not end up dividing to zero, which would put us to sleep
     98 		// indefinitely...
     99 		timeout = timediv(ns, 1000, nil)
    100 		if timeout == 0 {
    101 			timeout = 1
    102 		}
    103 	}
    104 
    105 	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
    106 	// expires or EBUSY if the mutex value does not match.
    107 	ret := sys_umtx_sleep(addr, int32(val), timeout)
    108 	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
    109 		return
    110 	}
    111 
    112 	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
    113 	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
    114 }
    115 
    116 //go:nosplit
    117 func futexwakeup(addr *uint32, cnt uint32) {
    118 	ret := sys_umtx_wakeup(addr, int32(cnt))
    119 	if ret >= 0 {
    120 		return
    121 	}
    122 
    123 	systemstack(func() {
    124 		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
    125 		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
    126 	})
    127 }
    128 
    129 func lwp_start(uintptr)
    130 
    131 // May run with m.p==nil, so write barriers are not allowed.
    132 //go:nowritebarrier
    133 func newosproc(mp *m, stk unsafe.Pointer) {
    134 	if false {
    135 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", funcPC(lwp_start), " id=", mp.id, " ostk=", &mp, "\n")
    136 	}
    137 
    138 	var oset sigset
    139 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    140 
    141 	params := lwpparams{
    142 		start_func: funcPC(lwp_start),
    143 		arg:        unsafe.Pointer(mp),
    144 		stack:      uintptr(stk),
    145 		tid1:       unsafe.Pointer(&mp.procid),
    146 		tid2:       nil,
    147 	}
    148 
    149 	// TODO: Check for error.
    150 	lwp_create(&params)
    151 	sigprocmask(_SIG_SETMASK, &oset, nil)
    152 }
    153 
    154 func osinit() {
    155 	ncpu = getncpu()
    156 	physPageSize = getPageSize()
    157 }
    158 
    159 var urandom_dev = []byte("/dev/urandom\x00")
    160 
    161 //go:nosplit
    162 func getRandomData(r []byte) {
    163 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    164 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    165 	closefd(fd)
    166 	extendRandom(r, int(n))
    167 }
    168 
    169 func goenvs() {
    170 	goenvs_unix()
    171 }
    172 
    173 // Called to initialize a new m (including the bootstrap m).
    174 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    175 func mpreinit(mp *m) {
    176 	mp.gsignal = malg(32 * 1024)
    177 	mp.gsignal.m = mp
    178 }
    179 
    180 // Called to initialize a new m (including the bootstrap m).
    181 // Called on the new thread, cannot allocate memory.
    182 func minit() {
    183 	// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
    184 	_g_ := getg()
    185 	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
    186 
    187 	minitSignals()
    188 }
    189 
    190 // Called from dropm to undo the effect of an minit.
    191 //go:nosplit
    192 func unminit() {
    193 	unminitSignals()
    194 }
    195 
    196 func memlimit() uintptr {
    197 	/*
    198 		                TODO: Convert to Go when something actually uses the result.
    199 
    200 				Rlimit rl;
    201 				extern byte runtimetext[], runtimeend[];
    202 				uintptr used;
    203 
    204 				if(runtimegetrlimit(RLIMIT_AS, &rl) != 0)
    205 					return 0;
    206 				if(rl.rlim_cur >= 0x7fffffff)
    207 					return 0;
    208 
    209 				// Estimate our VM footprint excluding the heap.
    210 				// Not an exact science: use size of binary plus
    211 				// some room for thread stacks.
    212 				used = runtimeend - runtimetext + (64<<20);
    213 				if(used >= rl.rlim_cur)
    214 					return 0;
    215 
    216 				// If there's not at least 16 MB left, we're probably
    217 				// not going to be able to do much. Treat as no limit.
    218 				rl.rlim_cur -= used;
    219 				if(rl.rlim_cur < (16<<20))
    220 					return 0;
    221 
    222 				return rl.rlim_cur - used;
    223 	*/
    224 	return 0
    225 }
    226 
    227 func sigtramp()
    228 
    229 type sigactiont struct {
    230 	sa_sigaction uintptr
    231 	sa_flags     int32
    232 	sa_mask      sigset
    233 }
    234 
    235 //go:nosplit
    236 //go:nowritebarrierrec
    237 func setsig(i uint32, fn uintptr) {
    238 	var sa sigactiont
    239 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
    240 	sa.sa_mask = sigset_all
    241 	if fn == funcPC(sighandler) {
    242 		fn = funcPC(sigtramp)
    243 	}
    244 	sa.sa_sigaction = fn
    245 	sigaction(i, &sa, nil)
    246 }
    247 
    248 //go:nosplit
    249 //go:nowritebarrierrec
    250 func setsigstack(i uint32) {
    251 	throw("setsigstack")
    252 }
    253 
    254 //go:nosplit
    255 //go:nowritebarrierrec
    256 func getsig(i uint32) uintptr {
    257 	var sa sigactiont
    258 	sigaction(i, nil, &sa)
    259 	return sa.sa_sigaction
    260 }
    261 
    262 // setSignaltstackSP sets the ss_sp field of a stackt.
    263 //go:nosplit
    264 func setSignalstackSP(s *stackt, sp uintptr) {
    265 	s.ss_sp = sp
    266 }
    267 
    268 //go:nosplit
    269 //go:nowritebarrierrec
    270 func sigaddset(mask *sigset, i int) {
    271 	mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
    272 }
    273 
    274 func sigdelset(mask *sigset, i int) {
    275 	mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
    276 }
    277 
    278 func (c *sigctxt) fixsigcode(sig uint32) {
    279 }
    280