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 (
      8 	"runtime/internal/atomic"
      9 	"unsafe"
     10 )
     11 
     12 const (
     13 	_SS_DISABLE  = 4
     14 	_SIG_BLOCK   = 1
     15 	_SIG_UNBLOCK = 2
     16 	_SIG_SETMASK = 3
     17 	_NSIG        = 33
     18 	_SI_USER     = 0
     19 
     20 	// From NetBSD's <sys/ucontext.h>
     21 	_UC_SIGMASK = 0x01
     22 	_UC_CPU     = 0x04
     23 
     24 	// From <sys/lwp.h>
     25 	_LWP_DETACHED = 0x00000040
     26 
     27 	_EAGAIN = 35
     28 )
     29 
     30 type mOS struct {
     31 	waitsemacount uint32
     32 }
     33 
     34 //go:noescape
     35 func setitimer(mode int32, new, old *itimerval)
     36 
     37 //go:noescape
     38 func sigaction(sig uint32, new, old *sigactiont)
     39 
     40 //go:noescape
     41 func sigaltstack(new, old *stackt)
     42 
     43 //go:noescape
     44 func sigprocmask(how int32, new, old *sigset)
     45 
     46 //go:noescape
     47 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
     48 
     49 func lwp_tramp()
     50 
     51 func raise(sig uint32)
     52 func raiseproc(sig uint32)
     53 
     54 //go:noescape
     55 func getcontext(ctxt unsafe.Pointer)
     56 
     57 //go:noescape
     58 func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
     59 
     60 //go:noescape
     61 func lwp_park(clockid, flags int32, ts *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
     62 
     63 //go:noescape
     64 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
     65 
     66 func lwp_self() int32
     67 
     68 func osyield()
     69 
     70 const (
     71 	_ESRCH     = 3
     72 	_ETIMEDOUT = 60
     73 
     74 	// From NetBSD's <sys/time.h>
     75 	_CLOCK_REALTIME  = 0
     76 	_CLOCK_VIRTUAL   = 1
     77 	_CLOCK_PROF      = 2
     78 	_CLOCK_MONOTONIC = 3
     79 
     80 	_TIMER_RELTIME = 0
     81 	_TIMER_ABSTIME = 1
     82 )
     83 
     84 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
     85 
     86 // From NetBSD's <sys/sysctl.h>
     87 const (
     88 	_CTL_HW      = 6
     89 	_HW_NCPU     = 3
     90 	_HW_PAGESIZE = 7
     91 )
     92 
     93 func getncpu() int32 {
     94 	mib := [2]uint32{_CTL_HW, _HW_NCPU}
     95 	out := uint32(0)
     96 	nout := unsafe.Sizeof(out)
     97 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
     98 	if ret >= 0 {
     99 		return int32(out)
    100 	}
    101 	return 1
    102 }
    103 
    104 func getPageSize() uintptr {
    105 	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
    106 	out := uint32(0)
    107 	nout := unsafe.Sizeof(out)
    108 	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
    109 	if ret >= 0 {
    110 		return uintptr(out)
    111 	}
    112 	return 0
    113 }
    114 
    115 //go:nosplit
    116 func semacreate(mp *m) {
    117 }
    118 
    119 //go:nosplit
    120 func semasleep(ns int64) int32 {
    121 	_g_ := getg()
    122 
    123 	// Compute sleep deadline.
    124 	var tsp *timespec
    125 	var ts timespec
    126 	if ns >= 0 {
    127 		var nsec int32
    128 		ts.set_sec(timediv(ns, 1000000000, &nsec))
    129 		ts.set_nsec(nsec)
    130 		tsp = &ts
    131 	}
    132 
    133 	for {
    134 		v := atomic.Load(&_g_.m.waitsemacount)
    135 		if v > 0 {
    136 			if atomic.Cas(&_g_.m.waitsemacount, v, v-1) {
    137 				return 0 // semaphore acquired
    138 			}
    139 			continue
    140 		}
    141 
    142 		// Sleep until unparked by semawakeup or timeout.
    143 		ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
    144 		if ret == _ETIMEDOUT {
    145 			return -1
    146 		} else if ret == _EINTR && ns >= 0 {
    147 			// Avoid sleeping forever if we keep getting
    148 			// interrupted (for example by the profiling
    149 			// timer). It would be if tsp upon return had the
    150 			// remaining time to sleep, but this is good enough.
    151 			var nsec int32
    152 			ns /= 2
    153 			ts.set_sec(timediv(ns, 1000000000, &nsec))
    154 			ts.set_nsec(nsec)
    155 		}
    156 	}
    157 }
    158 
    159 //go:nosplit
    160 func semawakeup(mp *m) {
    161 	atomic.Xadd(&mp.waitsemacount, 1)
    162 	// From NetBSD's _lwp_unpark(2) manual:
    163 	// "If the target LWP is not currently waiting, it will return
    164 	// immediately upon the next call to _lwp_park()."
    165 	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
    166 	if ret != 0 && ret != _ESRCH {
    167 		// semawakeup can be called on signal stack.
    168 		systemstack(func() {
    169 			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
    170 		})
    171 	}
    172 }
    173 
    174 // May run with m.p==nil, so write barriers are not allowed.
    175 //go:nowritebarrier
    176 func newosproc(mp *m, stk unsafe.Pointer) {
    177 	if false {
    178 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
    179 	}
    180 
    181 	var uc ucontextt
    182 	getcontext(unsafe.Pointer(&uc))
    183 
    184 	// _UC_SIGMASK does not seem to work here.
    185 	// It would be nice if _UC_SIGMASK and _UC_STACK
    186 	// worked so that we could do all the work setting
    187 	// the sigmask and the stack here, instead of setting
    188 	// the mask here and the stack in netbsdMstart.
    189 	// For now do the blocking manually.
    190 	uc.uc_flags = _UC_SIGMASK | _UC_CPU
    191 	uc.uc_link = nil
    192 	uc.uc_sigmask = sigset_all
    193 
    194 	var oset sigset
    195 	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
    196 
    197 	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart))
    198 
    199 	ret := lwp_create(unsafe.Pointer(&uc), _LWP_DETACHED, unsafe.Pointer(&mp.procid))
    200 	sigprocmask(_SIG_SETMASK, &oset, nil)
    201 	if ret < 0 {
    202 		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
    203 		if ret == -_EAGAIN {
    204 			println("runtime: may need to increase max user processes (ulimit -p)")
    205 		}
    206 		throw("runtime.newosproc")
    207 	}
    208 }
    209 
    210 // netbsdMStart is the function call that starts executing a newly
    211 // created thread. On NetBSD, a new thread inherits the signal stack
    212 // of the creating thread. That confuses minit, so we remove that
    213 // signal stack here before calling the regular mstart. It's a bit
    214 // baroque to remove a signal stack here only to add one in minit, but
    215 // it's a simple change that keeps NetBSD working like other OS's.
    216 // At this point all signals are blocked, so there is no race.
    217 //go:nosplit
    218 func netbsdMstart() {
    219 	st := stackt{ss_flags: _SS_DISABLE}
    220 	sigaltstack(&st, nil)
    221 	mstart()
    222 }
    223 
    224 func osinit() {
    225 	ncpu = getncpu()
    226 	physPageSize = getPageSize()
    227 }
    228 
    229 var urandom_dev = []byte("/dev/urandom\x00")
    230 
    231 //go:nosplit
    232 func getRandomData(r []byte) {
    233 	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
    234 	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
    235 	closefd(fd)
    236 	extendRandom(r, int(n))
    237 }
    238 
    239 func goenvs() {
    240 	goenvs_unix()
    241 }
    242 
    243 // Called to initialize a new m (including the bootstrap m).
    244 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
    245 func mpreinit(mp *m) {
    246 	mp.gsignal = malg(32 * 1024)
    247 	mp.gsignal.m = mp
    248 }
    249 
    250 // Called to initialize a new m (including the bootstrap m).
    251 // Called on the new thread, cannot allocate memory.
    252 func minit() {
    253 	_g_ := getg()
    254 	_g_.m.procid = uint64(lwp_self())
    255 
    256 	// On NetBSD a thread created by pthread_create inherits the
    257 	// signal stack of the creating thread. We always create a
    258 	// new signal stack here, to avoid having two Go threads using
    259 	// the same signal stack. This breaks the case of a thread
    260 	// created in C that calls sigaltstack and then calls a Go
    261 	// function, because we will lose track of the C code's
    262 	// sigaltstack, but it's the best we can do.
    263 	signalstack(&_g_.m.gsignal.stack)
    264 	_g_.m.newSigstack = true
    265 
    266 	minitSignalMask()
    267 }
    268 
    269 // Called from dropm to undo the effect of an minit.
    270 //go:nosplit
    271 func unminit() {
    272 	unminitSignals()
    273 }
    274 
    275 func memlimit() uintptr {
    276 	return 0
    277 }
    278 
    279 func sigtramp()
    280 
    281 type sigactiont struct {
    282 	sa_sigaction uintptr
    283 	sa_mask      sigset
    284 	sa_flags     int32
    285 }
    286 
    287 //go:nosplit
    288 //go:nowritebarrierrec
    289 func setsig(i uint32, fn uintptr) {
    290 	var sa sigactiont
    291 	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
    292 	sa.sa_mask = sigset_all
    293 	if fn == funcPC(sighandler) {
    294 		fn = funcPC(sigtramp)
    295 	}
    296 	sa.sa_sigaction = fn
    297 	sigaction(i, &sa, nil)
    298 }
    299 
    300 //go:nosplit
    301 //go:nowritebarrierrec
    302 func setsigstack(i uint32) {
    303 	throw("setsigstack")
    304 }
    305 
    306 //go:nosplit
    307 //go:nowritebarrierrec
    308 func getsig(i uint32) uintptr {
    309 	var sa sigactiont
    310 	sigaction(i, nil, &sa)
    311 	return sa.sa_sigaction
    312 }
    313 
    314 // setSignaltstackSP sets the ss_sp field of a stackt.
    315 //go:nosplit
    316 func setSignalstackSP(s *stackt, sp uintptr) {
    317 	s.ss_sp = sp
    318 }
    319 
    320 //go:nosplit
    321 //go:nowritebarrierrec
    322 func sigaddset(mask *sigset, i int) {
    323 	mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
    324 }
    325 
    326 func sigdelset(mask *sigset, i int) {
    327 	mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
    328 }
    329 
    330 func (c *sigctxt) fixsigcode(sig uint32) {
    331 }
    332