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 "internal/abi" 9 "internal/runtime/atomic" 10 "unsafe" 11) 12 13type mOS struct { 14 waitsemacount uint32 15} 16 17const ( 18 _ESRCH = 3 19 _EWOULDBLOCK = _EAGAIN 20 _ENOTSUP = 91 21 22 // From OpenBSD's sys/time.h 23 _CLOCK_REALTIME = 0 24 _CLOCK_VIRTUAL = 1 25 _CLOCK_PROF = 2 26 _CLOCK_MONOTONIC = 3 27) 28 29type sigset uint32 30 31var sigset_all = ^sigset(0) 32 33// From OpenBSD's <sys/sysctl.h> 34const ( 35 _CTL_HW = 6 36 _HW_NCPU = 3 37 _HW_PAGESIZE = 7 38 _HW_NCPUONLINE = 25 39) 40 41func sysctlInt(mib []uint32) (int32, bool) { 42 var out int32 43 nout := unsafe.Sizeof(out) 44 ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 45 if ret < 0 { 46 return 0, false 47 } 48 return out, true 49} 50 51func sysctlUint64(mib []uint32) (uint64, bool) { 52 var out uint64 53 nout := unsafe.Sizeof(out) 54 ret := sysctl(&mib[0], uint32(len(mib)), (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 55 if ret < 0 { 56 return 0, false 57 } 58 return out, true 59} 60 61//go:linkname internal_cpu_sysctlUint64 internal/cpu.sysctlUint64 62func internal_cpu_sysctlUint64(mib []uint32) (uint64, bool) { 63 return sysctlUint64(mib) 64} 65 66func getncpu() int32 { 67 // Try hw.ncpuonline first because hw.ncpu would report a number twice as 68 // high as the actual CPUs running on OpenBSD 6.4 with hyperthreading 69 // disabled (hw.smt=0). See https://golang.org/issue/30127 70 if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPUONLINE}); ok { 71 return int32(n) 72 } 73 if n, ok := sysctlInt([]uint32{_CTL_HW, _HW_NCPU}); ok { 74 return int32(n) 75 } 76 return 1 77} 78 79func getPageSize() uintptr { 80 if ps, ok := sysctlInt([]uint32{_CTL_HW, _HW_PAGESIZE}); ok { 81 return uintptr(ps) 82 } 83 return 0 84} 85 86//go:nosplit 87func semacreate(mp *m) { 88} 89 90//go:nosplit 91func semasleep(ns int64) int32 { 92 gp := getg() 93 94 // Compute sleep deadline. 95 var tsp *timespec 96 if ns >= 0 { 97 var ts timespec 98 ts.setNsec(ns + nanotime()) 99 tsp = &ts 100 } 101 102 for { 103 v := atomic.Load(&gp.m.waitsemacount) 104 if v > 0 { 105 if atomic.Cas(&gp.m.waitsemacount, v, v-1) { 106 return 0 // semaphore acquired 107 } 108 continue 109 } 110 111 // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. 112 // 113 // From OpenBSD's __thrsleep(2) manual: 114 // "The abort argument, if not NULL, points to an int that will 115 // be examined [...] immediately before blocking. If that int 116 // is non-zero then __thrsleep() will immediately return EINTR 117 // without blocking." 118 ret := thrsleep(uintptr(unsafe.Pointer(&gp.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &gp.m.waitsemacount) 119 if ret == _EWOULDBLOCK { 120 return -1 121 } 122 } 123} 124 125//go:nosplit 126func semawakeup(mp *m) { 127 atomic.Xadd(&mp.waitsemacount, 1) 128 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) 129 if ret != 0 && ret != _ESRCH { 130 // semawakeup can be called on signal stack. 131 systemstack(func() { 132 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 133 }) 134 } 135} 136 137func osinit() { 138 ncpu = getncpu() 139 physPageSize = getPageSize() 140} 141 142var urandom_dev = []byte("/dev/urandom\x00") 143 144//go:nosplit 145func readRandom(r []byte) int { 146 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 147 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 148 closefd(fd) 149 return int(n) 150} 151 152func goenvs() { 153 goenvs_unix() 154} 155 156// Called to initialize a new m (including the bootstrap m). 157// Called on the parent thread (main thread in case of bootstrap), can allocate memory. 158func mpreinit(mp *m) { 159 gsignalSize := int32(32 * 1024) 160 if GOARCH == "mips64" { 161 gsignalSize = int32(64 * 1024) 162 } 163 mp.gsignal = malg(gsignalSize) 164 mp.gsignal.m = mp 165} 166 167// Called to initialize a new m (including the bootstrap m). 168// Called on the new thread, can not allocate memory. 169func minit() { 170 getg().m.procid = uint64(getthrid()) 171 minitSignals() 172} 173 174// Called from dropm to undo the effect of an minit. 175// 176//go:nosplit 177func unminit() { 178 unminitSignals() 179 getg().m.procid = 0 180} 181 182// Called from exitm, but not from drop, to undo the effect of thread-owned 183// resources in minit, semacreate, or elsewhere. Do not take locks after calling this. 184func mdestroy(mp *m) { 185} 186 187func sigtramp() 188 189type sigactiont struct { 190 sa_sigaction uintptr 191 sa_mask uint32 192 sa_flags int32 193} 194 195//go:nosplit 196//go:nowritebarrierrec 197func setsig(i uint32, fn uintptr) { 198 var sa sigactiont 199 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 200 sa.sa_mask = uint32(sigset_all) 201 if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go 202 fn = abi.FuncPCABI0(sigtramp) 203 } 204 sa.sa_sigaction = fn 205 sigaction(i, &sa, nil) 206} 207 208//go:nosplit 209//go:nowritebarrierrec 210func setsigstack(i uint32) { 211 throw("setsigstack") 212} 213 214//go:nosplit 215//go:nowritebarrierrec 216func getsig(i uint32) uintptr { 217 var sa sigactiont 218 sigaction(i, nil, &sa) 219 return sa.sa_sigaction 220} 221 222// setSignalstackSP sets the ss_sp field of a stackt. 223// 224//go:nosplit 225func setSignalstackSP(s *stackt, sp uintptr) { 226 s.ss_sp = sp 227} 228 229//go:nosplit 230//go:nowritebarrierrec 231func sigaddset(mask *sigset, i int) { 232 *mask |= 1 << (uint32(i) - 1) 233} 234 235func sigdelset(mask *sigset, i int) { 236 *mask &^= 1 << (uint32(i) - 1) 237} 238 239//go:nosplit 240func (c *sigctxt) fixsigcode(sig uint32) { 241} 242 243func setProcessCPUProfiler(hz int32) { 244 setProcessCPUProfilerTimer(hz) 245} 246 247func setThreadCPUProfiler(hz int32) { 248 setThreadCPUProfilerHz(hz) 249} 250 251//go:nosplit 252func validSIGPROF(mp *m, c *sigctxt) bool { 253 return true 254} 255 256func osStackAlloc(s *mspan) { 257 osStackRemap(s, _MAP_STACK) 258} 259 260func osStackFree(s *mspan) { 261 // Undo MAP_STACK. 262 osStackRemap(s, 0) 263} 264 265func osStackRemap(s *mspan, flags int32) { 266 a, err := mmap(unsafe.Pointer(s.base()), s.npages*pageSize, _PROT_READ|_PROT_WRITE, _MAP_PRIVATE|_MAP_ANON|_MAP_FIXED|flags, -1, 0) 267 if err != 0 || uintptr(a) != s.base() { 268 print("runtime: remapping stack memory ", hex(s.base()), " ", s.npages*pageSize, " a=", a, " err=", err, "\n") 269 throw("remapping stack memory failed") 270 } 271} 272 273//go:nosplit 274func raise(sig uint32) { 275 thrkill(getthrid(), int(sig)) 276} 277 278func signalM(mp *m, sig int) { 279 thrkill(int32(mp.procid), sig) 280} 281 282// sigPerThreadSyscall is only used on linux, so we assign a bogus signal 283// number. 284const sigPerThreadSyscall = 1 << 31 285 286//go:nosplit 287func runPerThreadSyscall() { 288 throw("runPerThreadSyscall only valid on linux") 289} 290