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 "unsafe" 11) 12 13const ( 14 _NSIG = 33 15 _SI_USER = 0 16 _SS_DISABLE = 4 17 _SIG_BLOCK = 1 18 _SIG_UNBLOCK = 2 19 _SIG_SETMASK = 3 20) 21 22type mOS struct{} 23 24//go:noescape 25func lwp_create(param *lwpparams) int32 26 27//go:noescape 28func sigaltstack(new, old *stackt) 29 30//go:noescape 31func sigaction(sig uint32, new, old *sigactiont) 32 33//go:noescape 34func sigprocmask(how int32, new, old *sigset) 35 36//go:noescape 37func setitimer(mode int32, new, old *itimerval) 38 39//go:noescape 40func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 41 42func raiseproc(sig uint32) 43 44func lwp_gettid() int32 45func lwp_kill(pid, tid int32, sig int) 46 47//go:noescape 48func sys_umtx_sleep(addr *uint32, val, timeout int32) int32 49 50//go:noescape 51func sys_umtx_wakeup(addr *uint32, val int32) int32 52 53func osyield() 54 55//go:nosplit 56func osyield_no_g() { 57 osyield() 58} 59 60func kqueue() int32 61 62//go:noescape 63func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 64 65func pipe2(flags int32) (r, w int32, errno int32) 66func fcntl(fd, cmd, arg int32) (ret int32, errno int32) 67 68func issetugid() int32 69 70// From DragonFly's <sys/sysctl.h> 71const ( 72 _CTL_HW = 6 73 _HW_NCPU = 3 74 _HW_PAGESIZE = 7 75) 76 77var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} 78 79func getncpu() int32 { 80 mib := [2]uint32{_CTL_HW, _HW_NCPU} 81 out := uint32(0) 82 nout := unsafe.Sizeof(out) 83 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 84 if ret >= 0 { 85 return int32(out) 86 } 87 return 1 88} 89 90func getPageSize() uintptr { 91 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} 92 out := uint32(0) 93 nout := unsafe.Sizeof(out) 94 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 95 if ret >= 0 { 96 return uintptr(out) 97 } 98 return 0 99} 100 101//go:nosplit 102func futexsleep(addr *uint32, val uint32, ns int64) { 103 systemstack(func() { 104 futexsleep1(addr, val, ns) 105 }) 106} 107 108func futexsleep1(addr *uint32, val uint32, ns int64) { 109 var timeout int32 110 if ns >= 0 { 111 // The timeout is specified in microseconds - ensure that we 112 // do not end up dividing to zero, which would put us to sleep 113 // indefinitely... 114 timeout = timediv(ns, 1000, nil) 115 if timeout == 0 { 116 timeout = 1 117 } 118 } 119 120 // sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout 121 // expires or EBUSY if the mutex value does not match. 122 ret := sys_umtx_sleep(addr, int32(val), timeout) 123 if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY { 124 return 125 } 126 127 print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n") 128 *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 129} 130 131//go:nosplit 132func futexwakeup(addr *uint32, cnt uint32) { 133 ret := sys_umtx_wakeup(addr, int32(cnt)) 134 if ret >= 0 { 135 return 136 } 137 138 systemstack(func() { 139 print("umtx_wake_addr=", addr, " ret=", ret, "\n") 140 *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 141 }) 142} 143 144func lwp_start(uintptr) 145 146// May run with m.p==nil, so write barriers are not allowed. 147// 148//go:nowritebarrier 149func newosproc(mp *m) { 150 stk := unsafe.Pointer(mp.g0.stack.hi) 151 if false { 152 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", abi.FuncPCABI0(lwp_start), " id=", mp.id, " ostk=", &mp, "\n") 153 } 154 155 var oset sigset 156 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 157 158 params := lwpparams{ 159 start_func: abi.FuncPCABI0(lwp_start), 160 arg: unsafe.Pointer(mp), 161 stack: uintptr(stk), 162 tid1: nil, // minit will record tid 163 tid2: nil, 164 } 165 166 // TODO: Check for error. 167 retryOnEAGAIN(func() int32 { 168 lwp_create(¶ms) 169 return 0 170 }) 171 sigprocmask(_SIG_SETMASK, &oset, nil) 172} 173 174func osinit() { 175 ncpu = getncpu() 176 if physPageSize == 0 { 177 physPageSize = getPageSize() 178 } 179} 180 181var urandom_dev = []byte("/dev/urandom\x00") 182 183//go:nosplit 184func readRandom(r []byte) int { 185 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 186 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 187 closefd(fd) 188 return int(n) 189} 190 191func goenvs() { 192 goenvs_unix() 193} 194 195// Called to initialize a new m (including the bootstrap m). 196// Called on the parent thread (main thread in case of bootstrap), can allocate memory. 197func mpreinit(mp *m) { 198 mp.gsignal = malg(32 * 1024) 199 mp.gsignal.m = mp 200} 201 202// Called to initialize a new m (including the bootstrap m). 203// Called on the new thread, cannot allocate memory. 204func minit() { 205 getg().m.procid = uint64(lwp_gettid()) 206 minitSignals() 207} 208 209// Called from dropm to undo the effect of an minit. 210// 211//go:nosplit 212func unminit() { 213 unminitSignals() 214 getg().m.procid = 0 215} 216 217// Called from exitm, but not from drop, to undo the effect of thread-owned 218// resources in minit, semacreate, or elsewhere. Do not take locks after calling this. 219func mdestroy(mp *m) { 220} 221 222func sigtramp() 223 224type sigactiont struct { 225 sa_sigaction uintptr 226 sa_flags int32 227 sa_mask sigset 228} 229 230//go:nosplit 231//go:nowritebarrierrec 232func setsig(i uint32, fn uintptr) { 233 var sa sigactiont 234 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 235 sa.sa_mask = sigset_all 236 if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go 237 fn = abi.FuncPCABI0(sigtramp) 238 } 239 sa.sa_sigaction = fn 240 sigaction(i, &sa, nil) 241} 242 243//go:nosplit 244//go:nowritebarrierrec 245func setsigstack(i uint32) { 246 throw("setsigstack") 247} 248 249//go:nosplit 250//go:nowritebarrierrec 251func getsig(i uint32) uintptr { 252 var sa sigactiont 253 sigaction(i, nil, &sa) 254 return sa.sa_sigaction 255} 256 257// setSignalstackSP sets the ss_sp field of a stackt. 258// 259//go:nosplit 260func setSignalstackSP(s *stackt, sp uintptr) { 261 s.ss_sp = sp 262} 263 264//go:nosplit 265//go:nowritebarrierrec 266func sigaddset(mask *sigset, i int) { 267 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) 268} 269 270func sigdelset(mask *sigset, i int) { 271 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 272} 273 274//go:nosplit 275func (c *sigctxt) fixsigcode(sig uint32) { 276} 277 278func setProcessCPUProfiler(hz int32) { 279 setProcessCPUProfilerTimer(hz) 280} 281 282func setThreadCPUProfiler(hz int32) { 283 setThreadCPUProfilerHz(hz) 284} 285 286//go:nosplit 287func validSIGPROF(mp *m, c *sigctxt) bool { 288 return true 289} 290 291func sysargs(argc int32, argv **byte) { 292 n := argc + 1 293 294 // skip over argv, envp to get to auxv 295 for argv_index(argv, n) != nil { 296 n++ 297 } 298 299 // skip NULL separator 300 n++ 301 302 auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize)) 303 pairs := sysauxv(auxvp[:]) 304 auxv = auxvp[: pairs*2 : pairs*2] 305} 306 307const ( 308 _AT_NULL = 0 309 _AT_PAGESZ = 6 310) 311 312func sysauxv(auxv []uintptr) (pairs int) { 313 var i int 314 for i = 0; auxv[i] != _AT_NULL; i += 2 { 315 tag, val := auxv[i], auxv[i+1] 316 switch tag { 317 case _AT_PAGESZ: 318 physPageSize = val 319 } 320 } 321 return i / 2 322} 323 324// raise sends a signal to the calling thread. 325// 326// It must be nosplit because it is used by the signal handler before 327// it definitely has a Go stack. 328// 329//go:nosplit 330func raise(sig uint32) { 331 lwp_kill(-1, lwp_gettid(), int(sig)) 332} 333 334func signalM(mp *m, sig int) { 335 lwp_kill(-1, int32(mp.procid), sig) 336} 337 338// sigPerThreadSyscall is only used on linux, so we assign a bogus signal 339// number. 340const sigPerThreadSyscall = 1 << 31 341 342//go:nosplit 343func runPerThreadSyscall() { 344 throw("runPerThreadSyscall only valid on linux") 345} 346