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