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