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