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