github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/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 "runtime/internal/sys" 10 "unsafe" 11 ) 12 13 const ( 14 _SS_DISABLE = 4 15 _SIG_BLOCK = 1 16 _SIG_UNBLOCK = 2 17 _SIG_SETMASK = 3 18 _NSIG = 33 19 _SI_USER = 0 20 21 // From NetBSD's <sys/ucontext.h> 22 _UC_SIGMASK = 0x01 23 _UC_CPU = 0x04 24 25 // From <sys/lwp.h> 26 _LWP_DETACHED = 0x00000040 27 28 _EAGAIN = 35 29 ) 30 31 type mOS struct { 32 waitsemacount uint32 33 } 34 35 //go:noescape 36 func setitimer(mode int32, new, old *itimerval) 37 38 //go:noescape 39 func sigaction(sig uint32, new, old *sigactiont) 40 41 //go:noescape 42 func sigaltstack(new, old *stackt) 43 44 //go:noescape 45 func sigprocmask(how int32, new, old *sigset) 46 47 //go:noescape 48 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 49 50 func lwp_tramp() 51 52 func raise(sig uint32) 53 func raiseproc(sig uint32) 54 55 //go:noescape 56 func getcontext(ctxt unsafe.Pointer) 57 58 //go:noescape 59 func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 60 61 //go:noescape 62 func lwp_park(clockid, flags int32, ts *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32 63 64 //go:noescape 65 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 66 67 func lwp_self() int32 68 69 func osyield() 70 71 func kqueue() int32 72 73 //go:noescape 74 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 75 func closeonexec(fd int32) 76 77 const ( 78 _ESRCH = 3 79 _ETIMEDOUT = 60 80 81 // From NetBSD's <sys/time.h> 82 _CLOCK_REALTIME = 0 83 _CLOCK_VIRTUAL = 1 84 _CLOCK_PROF = 2 85 _CLOCK_MONOTONIC = 3 86 87 _TIMER_RELTIME = 0 88 _TIMER_ABSTIME = 1 89 ) 90 91 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} 92 93 // From NetBSD's <sys/sysctl.h> 94 const ( 95 _CTL_HW = 6 96 _HW_NCPU = 3 97 _HW_PAGESIZE = 7 98 ) 99 100 func getncpu() int32 { 101 mib := [2]uint32{_CTL_HW, _HW_NCPU} 102 out := uint32(0) 103 nout := unsafe.Sizeof(out) 104 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 105 if ret >= 0 { 106 return int32(out) 107 } 108 return 1 109 } 110 111 func getPageSize() uintptr { 112 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} 113 out := uint32(0) 114 nout := unsafe.Sizeof(out) 115 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 116 if ret >= 0 { 117 return uintptr(out) 118 } 119 return 0 120 } 121 122 //go:nosplit 123 func semacreate(mp *m) { 124 } 125 126 //go:nosplit 127 func semasleep(ns int64) int32 { 128 _g_ := getg() 129 var deadline int64 130 if ns >= 0 { 131 deadline = nanotime() + ns 132 } 133 134 for { 135 v := atomic.Load(&_g_.m.waitsemacount) 136 if v > 0 { 137 if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { 138 return 0 // semaphore acquired 139 } 140 continue 141 } 142 143 // Sleep until unparked by semawakeup or timeout. 144 var tsp *timespec 145 var ts timespec 146 if ns >= 0 { 147 wait := deadline - nanotime() 148 if wait <= 0 { 149 return -1 150 } 151 var nsec int32 152 ts.set_sec(timediv(wait, 1000000000, &nsec)) 153 ts.set_nsec(nsec) 154 tsp = &ts 155 } 156 ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) 157 if ret == _ETIMEDOUT { 158 return -1 159 } 160 } 161 } 162 163 //go:nosplit 164 func semawakeup(mp *m) { 165 atomic.Xadd(&mp.waitsemacount, 1) 166 // From NetBSD's _lwp_unpark(2) manual: 167 // "If the target LWP is not currently waiting, it will return 168 // immediately upon the next call to _lwp_park()." 169 ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) 170 if ret != 0 && ret != _ESRCH { 171 // semawakeup can be called on signal stack. 172 systemstack(func() { 173 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 174 }) 175 } 176 } 177 178 // May run with m.p==nil, so write barriers are not allowed. 179 //go:nowritebarrier 180 func newosproc(mp *m) { 181 stk := unsafe.Pointer(mp.g0.stack.hi) 182 if false { 183 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 184 } 185 186 var uc ucontextt 187 getcontext(unsafe.Pointer(&uc)) 188 189 // _UC_SIGMASK does not seem to work here. 190 // It would be nice if _UC_SIGMASK and _UC_STACK 191 // worked so that we could do all the work setting 192 // the sigmask and the stack here, instead of setting 193 // the mask here and the stack in netbsdMstart. 194 // For now do the blocking manually. 195 uc.uc_flags = _UC_SIGMASK | _UC_CPU 196 uc.uc_link = nil 197 uc.uc_sigmask = sigset_all 198 199 var oset sigset 200 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 201 202 lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart)) 203 204 ret := lwp_create(unsafe.Pointer(&uc), _LWP_DETACHED, unsafe.Pointer(&mp.procid)) 205 sigprocmask(_SIG_SETMASK, &oset, nil) 206 if ret < 0 { 207 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 208 if ret == -_EAGAIN { 209 println("runtime: may need to increase max user processes (ulimit -p)") 210 } 211 throw("runtime.newosproc") 212 } 213 } 214 215 // netbsdMStart is the function call that starts executing a newly 216 // created thread. On NetBSD, a new thread inherits the signal stack 217 // of the creating thread. That confuses minit, so we remove that 218 // signal stack here before calling the regular mstart. It's a bit 219 // baroque to remove a signal stack here only to add one in minit, but 220 // it's a simple change that keeps NetBSD working like other OS's. 221 // At this point all signals are blocked, so there is no race. 222 //go:nosplit 223 func netbsdMstart() { 224 st := stackt{ss_flags: _SS_DISABLE} 225 sigaltstack(&st, nil) 226 mstart() 227 } 228 229 func osinit() { 230 ncpu = getncpu() 231 if physPageSize == 0 { 232 physPageSize = getPageSize() 233 } 234 } 235 236 var urandom_dev = []byte("/dev/urandom\x00") 237 238 //go:nosplit 239 func getRandomData(r []byte) { 240 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 241 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 242 closefd(fd) 243 extendRandom(r, int(n)) 244 } 245 246 func goenvs() { 247 goenvs_unix() 248 } 249 250 // Called to initialize a new m (including the bootstrap m). 251 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 252 func mpreinit(mp *m) { 253 mp.gsignal = malg(32 * 1024) 254 mp.gsignal.m = mp 255 } 256 257 // Called to initialize a new m (including the bootstrap m). 258 // Called on the new thread, cannot allocate memory. 259 func minit() { 260 _g_ := getg() 261 _g_.m.procid = uint64(lwp_self()) 262 263 // On NetBSD a thread created by pthread_create inherits the 264 // signal stack of the creating thread. We always create a 265 // new signal stack here, to avoid having two Go threads using 266 // the same signal stack. This breaks the case of a thread 267 // created in C that calls sigaltstack and then calls a Go 268 // function, because we will lose track of the C code's 269 // sigaltstack, but it's the best we can do. 270 signalstack(&_g_.m.gsignal.stack) 271 _g_.m.newSigstack = true 272 273 minitSignalMask() 274 } 275 276 // Called from dropm to undo the effect of an minit. 277 //go:nosplit 278 func unminit() { 279 unminitSignals() 280 } 281 282 func sigtramp() 283 284 type sigactiont struct { 285 sa_sigaction uintptr 286 sa_mask sigset 287 sa_flags int32 288 } 289 290 //go:nosplit 291 //go:nowritebarrierrec 292 func setsig(i uint32, fn uintptr) { 293 var sa sigactiont 294 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 295 sa.sa_mask = sigset_all 296 if fn == funcPC(sighandler) { 297 fn = funcPC(sigtramp) 298 } 299 sa.sa_sigaction = fn 300 sigaction(i, &sa, nil) 301 } 302 303 //go:nosplit 304 //go:nowritebarrierrec 305 func setsigstack(i uint32) { 306 throw("setsigstack") 307 } 308 309 //go:nosplit 310 //go:nowritebarrierrec 311 func getsig(i uint32) uintptr { 312 var sa sigactiont 313 sigaction(i, nil, &sa) 314 return sa.sa_sigaction 315 } 316 317 // setSignaltstackSP sets the ss_sp field of a stackt. 318 //go:nosplit 319 func setSignalstackSP(s *stackt, sp uintptr) { 320 s.ss_sp = sp 321 } 322 323 //go:nosplit 324 //go:nowritebarrierrec 325 func sigaddset(mask *sigset, i int) { 326 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) 327 } 328 329 func sigdelset(mask *sigset, i int) { 330 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 331 } 332 333 func (c *sigctxt) fixsigcode(sig uint32) { 334 } 335 336 func sysargs(argc int32, argv **byte) { 337 n := argc + 1 338 339 // skip over argv, envp to get to auxv 340 for argv_index(argv, n) != nil { 341 n++ 342 } 343 344 // skip NULL separator 345 n++ 346 347 // now argv+n is auxv 348 auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) 349 sysauxv(auxv[:]) 350 } 351 352 const ( 353 _AT_NULL = 0 // Terminates the vector 354 _AT_PAGESZ = 6 // Page size in bytes 355 ) 356 357 func sysauxv(auxv []uintptr) { 358 for i := 0; auxv[i] != _AT_NULL; i += 2 { 359 tag, val := auxv[i], auxv[i+1] 360 switch tag { 361 case _AT_PAGESZ: 362 physPageSize = val 363 } 364 } 365 }