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