github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/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 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_SIGMASK does not seem to work here. 171 // It would be nice if _UC_SIGMASK and _UC_STACK 172 // worked so that we could do all the work setting 173 // the sigmask and the stack here, instead of setting 174 // the mask here and the stack in netbsdMstart. 175 // For now do the blocking manually. 176 uc.uc_flags = _UC_SIGMASK | _UC_CPU 177 uc.uc_link = nil 178 uc.uc_sigmask = sigset_all 179 180 var oset sigset 181 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 182 183 lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart)) 184 185 ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) 186 sigprocmask(_SIG_SETMASK, &oset, nil) 187 if ret < 0 { 188 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 189 if ret == -_EAGAIN { 190 println("runtime: may need to increase max user processes (ulimit -p)") 191 } 192 throw("runtime.newosproc") 193 } 194 } 195 196 // netbsdMStart is the function call that starts executing a newly 197 // created thread. On NetBSD, a new thread inherits the signal stack 198 // of the creating thread. That confuses minit, so we remove that 199 // signal stack here before calling the regular mstart. It's a bit 200 // baroque to remove a signal stack here only to add one in minit, but 201 // it's a simple change that keeps NetBSD working like other OS's. 202 // At this point all signals are blocked, so there is no race. 203 //go:nosplit 204 func netbsdMstart() { 205 st := stackt{ss_flags: _SS_DISABLE} 206 sigaltstack(&st, nil) 207 mstart() 208 } 209 210 func osinit() { 211 ncpu = getncpu() 212 physPageSize = getPageSize() 213 } 214 215 var urandom_dev = []byte("/dev/urandom\x00") 216 217 //go:nosplit 218 func getRandomData(r []byte) { 219 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 220 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 221 closefd(fd) 222 extendRandom(r, int(n)) 223 } 224 225 func goenvs() { 226 goenvs_unix() 227 } 228 229 // Called to initialize a new m (including the bootstrap m). 230 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 231 func mpreinit(mp *m) { 232 mp.gsignal = malg(32 * 1024) 233 mp.gsignal.m = mp 234 } 235 236 // Called to initialize a new m (including the bootstrap m). 237 // Called on the new thread, cannot allocate memory. 238 func minit() { 239 _g_ := getg() 240 _g_.m.procid = uint64(lwp_self()) 241 242 // On NetBSD a thread created by pthread_create inherits the 243 // signal stack of the creating thread. We always create a 244 // new signal stack here, to avoid having two Go threads using 245 // the same signal stack. This breaks the case of a thread 246 // created in C that calls sigaltstack and then calls a Go 247 // function, because we will lose track of the C code's 248 // sigaltstack, but it's the best we can do. 249 signalstack(&_g_.m.gsignal.stack) 250 _g_.m.newSigstack = true 251 252 minitSignalMask() 253 } 254 255 // Called from dropm to undo the effect of an minit. 256 //go:nosplit 257 func unminit() { 258 unminitSignals() 259 } 260 261 func memlimit() uintptr { 262 return 0 263 } 264 265 func sigtramp() 266 267 type sigactiont struct { 268 sa_sigaction uintptr 269 sa_mask sigset 270 sa_flags int32 271 } 272 273 //go:nosplit 274 //go:nowritebarrierrec 275 func setsig(i uint32, fn uintptr) { 276 var sa sigactiont 277 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 278 sa.sa_mask = sigset_all 279 if fn == funcPC(sighandler) { 280 fn = funcPC(sigtramp) 281 } 282 sa.sa_sigaction = fn 283 sigaction(i, &sa, nil) 284 } 285 286 //go:nosplit 287 //go:nowritebarrierrec 288 func setsigstack(i uint32) { 289 throw("setsigstack") 290 } 291 292 //go:nosplit 293 //go:nowritebarrierrec 294 func getsig(i uint32) uintptr { 295 var sa sigactiont 296 sigaction(i, nil, &sa) 297 return sa.sa_sigaction 298 } 299 300 // setSignaltstackSP sets the ss_sp field of a stackt. 301 //go:nosplit 302 func setSignalstackSP(s *stackt, sp uintptr) { 303 s.ss_sp = sp 304 } 305 306 //go:nosplit 307 //go:nowritebarrierrec 308 func sigaddset(mask *sigset, i int) { 309 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) 310 } 311 312 func sigdelset(mask *sigset, i int) { 313 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 314 } 315 316 func (c *sigctxt) fixsigcode(sig uint32) { 317 }