github.com/euank/go@v0.0.0-20160829210321-495514729181/src/runtime/os_netbsd.go (about) 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 int32, new, old *sigactiont) 36 37 //go:noescape 38 func sigaltstack(new, old *sigaltstackt) 39 40 //go:noescape 41 func sigprocmask(mode 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 int32) 49 func raiseproc(sig int32) 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 ) 85 86 func getncpu() int32 { 87 mib := [2]uint32{_CTL_HW, _HW_NCPU} 88 out := uint32(0) 89 nout := unsafe.Sizeof(out) 90 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 91 if ret >= 0 { 92 return int32(out) 93 } 94 return 1 95 } 96 97 //go:nosplit 98 func semacreate(mp *m) { 99 } 100 101 //go:nosplit 102 func semasleep(ns int64) int32 { 103 _g_ := getg() 104 105 // Compute sleep deadline. 106 var tsp *timespec 107 if ns >= 0 { 108 var ts timespec 109 var nsec int32 110 ns += nanotime() 111 ts.set_sec(timediv(ns, 1000000000, &nsec)) 112 ts.set_nsec(nsec) 113 tsp = &ts 114 } 115 116 for { 117 v := atomic.Load(&_g_.m.waitsemacount) 118 if v > 0 { 119 if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { 120 return 0 // semaphore acquired 121 } 122 continue 123 } 124 125 // Sleep until unparked by semawakeup or timeout. 126 ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) 127 if ret == _ETIMEDOUT { 128 return -1 129 } 130 } 131 } 132 133 //go:nosplit 134 func semawakeup(mp *m) { 135 atomic.Xadd(&mp.waitsemacount, 1) 136 // From NetBSD's _lwp_unpark(2) manual: 137 // "If the target LWP is not currently waiting, it will return 138 // immediately upon the next call to _lwp_park()." 139 ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) 140 if ret != 0 && ret != _ESRCH { 141 // semawakeup can be called on signal stack. 142 systemstack(func() { 143 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 144 }) 145 } 146 } 147 148 // May run with m.p==nil, so write barriers are not allowed. 149 //go:nowritebarrier 150 func newosproc(mp *m, stk unsafe.Pointer) { 151 if false { 152 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 153 } 154 155 var uc ucontextt 156 getcontext(unsafe.Pointer(&uc)) 157 158 uc.uc_flags = _UC_SIGMASK | _UC_CPU 159 uc.uc_link = nil 160 uc.uc_sigmask = sigset_all 161 162 lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart)) 163 164 ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) 165 if ret < 0 { 166 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 167 if ret == -_EAGAIN { 168 println("runtime: may need to increase max user processes (ulimit -p)") 169 } 170 throw("runtime.newosproc") 171 } 172 } 173 174 // netbsdMStart is the function call that starts executing a newly 175 // created thread. On NetBSD, a new thread inherits the signal stack 176 // of the creating thread. That confuses minit, so we remove that 177 // signal stack here before calling the regular mstart. It's a bit 178 // baroque to remove a signal stack here only to add one in minit, but 179 // it's a simple change that keeps NetBSD working like other OS's. 180 // At this point all signals are blocked, so there is no race. 181 //go:nosplit 182 func netbsdMstart() { 183 signalstack(nil) 184 mstart() 185 } 186 187 func osinit() { 188 ncpu = getncpu() 189 } 190 191 var urandom_dev = []byte("/dev/urandom\x00") 192 193 //go:nosplit 194 func getRandomData(r []byte) { 195 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 196 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 197 closefd(fd) 198 extendRandom(r, int(n)) 199 } 200 201 func goenvs() { 202 goenvs_unix() 203 } 204 205 // Called to initialize a new m (including the bootstrap m). 206 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 207 func mpreinit(mp *m) { 208 mp.gsignal = malg(32 * 1024) 209 mp.gsignal.m = mp 210 } 211 212 //go:nosplit 213 func msigsave(mp *m) { 214 sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) 215 } 216 217 //go:nosplit 218 func msigrestore(sigmask sigset) { 219 sigprocmask(_SIG_SETMASK, &sigmask, nil) 220 } 221 222 //go:nosplit 223 func sigblock() { 224 sigprocmask(_SIG_SETMASK, &sigset_all, nil) 225 } 226 227 // Called to initialize a new m (including the bootstrap m). 228 // Called on the new thread, cannot allocate memory. 229 func minit() { 230 _g_ := getg() 231 _g_.m.procid = uint64(lwp_self()) 232 233 // Initialize signal handling. 234 235 // On NetBSD a thread created by pthread_create inherits the 236 // signal stack of the creating thread. We always create a 237 // new signal stack here, to avoid having two Go threads using 238 // the same signal stack. This breaks the case of a thread 239 // created in C that calls sigaltstack and then calls a Go 240 // function, because we will lose track of the C code's 241 // sigaltstack, but it's the best we can do. 242 signalstack(&_g_.m.gsignal.stack) 243 _g_.m.newSigstack = true 244 245 // restore signal mask from m.sigmask and unblock essential signals 246 nmask := _g_.m.sigmask 247 for i := range sigtable { 248 if sigtable[i].flags&_SigUnblock != 0 { 249 nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 250 } 251 } 252 sigprocmask(_SIG_SETMASK, &nmask, nil) 253 } 254 255 // Called from dropm to undo the effect of an minit. 256 //go:nosplit 257 func unminit() { 258 if getg().m.newSigstack { 259 signalstack(nil) 260 } 261 } 262 263 func memlimit() uintptr { 264 return 0 265 } 266 267 func sigtramp() 268 269 type sigactiont struct { 270 sa_sigaction uintptr 271 sa_mask sigset 272 sa_flags int32 273 } 274 275 //go:nosplit 276 //go:nowritebarrierrec 277 func setsig(i int32, fn uintptr, restart bool) { 278 var sa sigactiont 279 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 280 if restart { 281 sa.sa_flags |= _SA_RESTART 282 } 283 sa.sa_mask = sigset_all 284 if fn == funcPC(sighandler) { 285 fn = funcPC(sigtramp) 286 } 287 sa.sa_sigaction = fn 288 sigaction(i, &sa, nil) 289 } 290 291 //go:nosplit 292 //go:nowritebarrierrec 293 func setsigstack(i int32) { 294 throw("setsigstack") 295 } 296 297 //go:nosplit 298 //go:nowritebarrierrec 299 func getsig(i int32) uintptr { 300 var sa sigactiont 301 sigaction(i, nil, &sa) 302 if sa.sa_sigaction == funcPC(sigtramp) { 303 return funcPC(sighandler) 304 } 305 return sa.sa_sigaction 306 } 307 308 //go:nosplit 309 func signalstack(s *stack) { 310 var st sigaltstackt 311 if s == nil { 312 st.ss_flags = _SS_DISABLE 313 } else { 314 st.ss_sp = s.lo 315 st.ss_size = s.hi - s.lo 316 st.ss_flags = 0 317 } 318 sigaltstack(&st, nil) 319 } 320 321 //go:nosplit 322 //go:nowritebarrierrec 323 func updatesigmask(m sigmask) { 324 var mask sigset 325 copy(mask.__bits[:], m[:]) 326 sigprocmask(_SIG_SETMASK, &mask, nil) 327 } 328 329 func unblocksig(sig int32) { 330 var mask sigset 331 mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) 332 sigprocmask(_SIG_UNBLOCK, &mask, nil) 333 }