1// Copyright 2011 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/atomic" 9 "runtime/internal/sys" 10 "unsafe" 11) 12 13type mOS struct { 14 waitsemacount uint32 15} 16 17//go:noescape 18func setitimer(mode int32, new, old *itimerval) 19 20//go:noescape 21func sigaction(sig uint32, new, old *sigactiont) 22 23//go:noescape 24func sigaltstack(new, old *stackt) 25 26//go:noescape 27func obsdsigprocmask(how int32, new sigset) sigset 28 29//go:nosplit 30//go:nowritebarrierrec 31func sigprocmask(how int32, new, old *sigset) { 32 n := sigset(0) 33 if new != nil { 34 n = *new 35 } 36 r := obsdsigprocmask(how, n) 37 if old != nil { 38 *old = r 39 } 40} 41 42//go:noescape 43func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 44 45func raiseproc(sig uint32) 46 47func getthrid() int32 48func thrkill(tid int32, sig int) 49 50//go:noescape 51func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32 52 53//go:noescape 54func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 55 56//go:noescape 57func thrwakeup(ident uintptr, n int32) int32 58 59func osyield() 60 61func kqueue() int32 62 63//go:noescape 64func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 65 66func pipe() (r, w int32, errno int32) 67func pipe2(flags int32) (r, w int32, errno int32) 68func closeonexec(fd int32) 69func setNonblock(fd int32) 70 71const ( 72 _ESRCH = 3 73 _EWOULDBLOCK = _EAGAIN 74 _ENOTSUP = 91 75 76 // From OpenBSD's sys/time.h 77 _CLOCK_REALTIME = 0 78 _CLOCK_VIRTUAL = 1 79 _CLOCK_PROF = 2 80 _CLOCK_MONOTONIC = 3 81) 82 83type sigset uint32 84 85var sigset_all = ^sigset(0) 86 87// From OpenBSD's <sys/sysctl.h> 88const ( 89 _CTL_KERN = 1 90 _KERN_OSREV = 3 91 92 _CTL_HW = 6 93 _HW_NCPU = 3 94 _HW_PAGESIZE = 7 95 _HW_NCPUONLINE = 25 96) 97 98func sysctlInt(mib []uint32) (int32, bool) { 99 var out int32 100 nout := unsafe.Sizeof(out) 101 ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 102 if ret < 0 { 103 return 0, false 104 } 105 return out, true 106} 107 108func getncpu() int32 { 109 // Try hw.ncpuonline first because hw.ncpu would report a number twice as 110 // high as the actual CPUs running on OpenBSD 6.4 with hyperthreading 111 // disabled (hw.smt=0). See https://golang.org/issue/30127 112 if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok { 113 return int32(n) 114 } 115 if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok { 116 return int32(n) 117 } 118 return 1 119} 120 121func getPageSize() uintptr { 122 if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok { 123 return uintptr(ps) 124 } 125 return 0 126} 127 128func getOSRev() int { 129 if osrev, ok := sysctlInt([]uint32{_CTL_KERN, _KERN_OSREV}); ok { 130 return int(osrev) 131 } 132 return 0 133} 134 135//go:nosplit 136func semacreate(mp *m) { 137} 138 139//go:nosplit 140func semasleep(ns int64) int32 { 141 _g_ := getg() 142 143 // Compute sleep deadline. 144 var tsp *timespec 145 if ns >= 0 { 146 var ts timespec 147 ts.setNsec(ns + nanotime()) 148 tsp = &ts 149 } 150 151 for { 152 v := atomic.Load(&_g_.m.waitsemacount) 153 if v > 0 { 154 if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { 155 return 0 // semaphore acquired 156 } 157 continue 158 } 159 160 // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. 161 // 162 // From OpenBSD's __thrsleep(2) manual: 163 // "The abort argument, if not NULL, points to an int that will 164 // be examined [...] immediately before blocking. If that int 165 // is non-zero then __thrsleep() will immediately return EINTR 166 // without blocking." 167 ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount) 168 if ret == _EWOULDBLOCK { 169 return -1 170 } 171 } 172} 173 174//go:nosplit 175func semawakeup(mp *m) { 176 atomic.Xadd(&mp.waitsemacount, 1) 177 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) 178 if ret != 0 && ret != _ESRCH { 179 // semawakeup can be called on signal stack. 180 systemstack(func() { 181 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 182 }) 183 } 184} 185 186// May run with m.p==nil, so write barriers are not allowed. 187//go:nowritebarrier 188func newosproc(mp *m) { 189 stk := unsafe.Pointer(mp.g0.stack.hi) 190 if false { 191 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 192 } 193 194 // Stack pointer must point inside stack area (as marked with MAP_STACK), 195 // rather than at the top of it. 196 param := tforkt{ 197 tf_tcb: unsafe.Pointer(&mp.tls[0]), 198 tf_tid: nil, // minit will record tid 199 tf_stack: uintptr(stk) - sys.PtrSize, 200 } 201 202 var oset sigset 203 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 204 ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) 205 sigprocmask(_SIG_SETMASK, &oset, nil) 206 207 if ret < 0 { 208 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 209 if ret == -_EAGAIN { 210 println("runtime: may need to increase max user processes (ulimit -p)") 211 } 212 throw("runtime.newosproc") 213 } 214} 215 216func osinit() { 217 ncpu = getncpu() 218 physPageSize = getPageSize() 219 haveMapStack = getOSRev() >= 201805 // OpenBSD 6.3 220} 221 222var urandom_dev = []byte("/dev/urandom\x00") 223 224//go:nosplit 225func getRandomData(r []byte) { 226 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 227 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 228 closefd(fd) 229 extendRandom(r, int(n)) 230} 231 232func goenvs() { 233 goenvs_unix() 234} 235 236// Called to initialize a new m (including the bootstrap m). 237// Called on the parent thread (main thread in case of bootstrap), can allocate memory. 238func mpreinit(mp *m) { 239 mp.gsignal = malg(32 * 1024) 240 mp.gsignal.m = mp 241} 242 243// Called to initialize a new m (including the bootstrap m). 244// Called on the new thread, can not allocate memory. 245func minit() { 246 getg().m.procid = uint64(getthrid()) 247 minitSignals() 248} 249 250// Called from dropm to undo the effect of an minit. 251//go:nosplit 252func unminit() { 253 unminitSignals() 254} 255 256func sigtramp() 257 258type sigactiont struct { 259 sa_sigaction uintptr 260 sa_mask uint32 261 sa_flags int32 262} 263 264//go:nosplit 265//go:nowritebarrierrec 266func setsig(i uint32, fn uintptr) { 267 var sa sigactiont 268 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 269 sa.sa_mask = uint32(sigset_all) 270 if fn == funcPC(sighandler) { 271 fn = funcPC(sigtramp) 272 } 273 sa.sa_sigaction = fn 274 sigaction(i, &sa, nil) 275} 276 277//go:nosplit 278//go:nowritebarrierrec 279func setsigstack(i uint32) { 280 throw("setsigstack") 281} 282 283//go:nosplit 284//go:nowritebarrierrec 285func getsig(i uint32) uintptr { 286 var sa sigactiont 287 sigaction(i, nil, &sa) 288 return sa.sa_sigaction 289} 290 291// setSignaltstackSP sets the ss_sp field of a stackt. 292//go:nosplit 293func setSignalstackSP(s *stackt, sp uintptr) { 294 s.ss_sp = sp 295} 296 297//go:nosplit 298//go:nowritebarrierrec 299func sigaddset(mask *sigset, i int) { 300 *mask |= 1 << (uint32(i) - 1) 301} 302 303func sigdelset(mask *sigset, i int) { 304 *mask &^= 1 << (uint32(i) - 1) 305} 306 307//go:nosplit 308func (c *sigctxt) fixsigcode(sig uint32) { 309} 310 311var haveMapStack = false 312 313func osStackAlloc(s *mspan) { 314 // OpenBSD 6.4+ requires that stacks be mapped with MAP_STACK. 315 // It will check this on entry to system calls, traps, and 316 // when switching to the alternate system stack. 317 // 318 // This function is called before s is used for any data, so 319 // it's safe to simply re-map it. 320 osStackRemap(s, _MAP_STACK) 321} 322 323func osStackFree(s *mspan) { 324 // Undo MAP_STACK. 325 osStackRemap(s, 0) 326} 327 328func osStackRemap(s *mspan, flags int32) { 329 if !haveMapStack { 330 // OpenBSD prior to 6.3 did not have MAP_STACK and so 331 // the following mmap will fail. But it also didn't 332 // require MAP_STACK (obviously), so there's no need 333 // to do the mmap. 334 return 335 } 336 a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0) 337 if err != 0 || uintptr(a) != s.base() { 338 print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n") 339 throw("remapping stack memory failed") 340 } 341} 342 343func raise(sig uint32) { 344 thrkill(getthrid(), int(sig)) 345} 346 347func signalM(mp *m, sig int) { 348 thrkill(int32(mp.procid), sig) 349} 350