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