github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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_HW = 6 36 _HW_NCPU = 3 37 _HW_PAGESIZE = 7 38 _HW_NCPUONLINE = 25 39 ) 40 41 func 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 51 func 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 62 func internal_cpu_sysctlUint64(mib []uint32) (uint64, bool) { 63 return sysctlUint64(mib) 64 } 65 66 func 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 79 func 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 87 func semacreate(mp *m) { 88 } 89 90 //go:nosplit 91 func 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 126 func 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 137 func osinit() { 138 ncpu = getncpu() 139 physPageSize = getPageSize() 140 } 141 142 var urandom_dev = []byte("/dev/urandom\x00") 143 144 //go:nosplit 145 func 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 152 func 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. 158 func 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. 169 func 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 177 func 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. 184 func mdestroy(mp *m) { 185 } 186 187 func sigtramp() 188 189 type sigactiont struct { 190 sa_sigaction uintptr 191 sa_mask uint32 192 sa_flags int32 193 } 194 195 //go:nosplit 196 //go:nowritebarrierrec 197 func 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 210 func setsigstack(i uint32) { 211 throw("setsigstack") 212 } 213 214 //go:nosplit 215 //go:nowritebarrierrec 216 func 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 225 func setSignalstackSP(s *stackt, sp uintptr) { 226 s.ss_sp = sp 227 } 228 229 //go:nosplit 230 //go:nowritebarrierrec 231 func sigaddset(mask *sigset, i int) { 232 *mask |= 1 << (uint32(i) - 1) 233 } 234 235 func sigdelset(mask *sigset, i int) { 236 *mask &^= 1 << (uint32(i) - 1) 237 } 238 239 //go:nosplit 240 func (c *sigctxt) fixsigcode(sig uint32) { 241 } 242 243 func setProcessCPUProfiler(hz int32) { 244 setProcessCPUProfilerTimer(hz) 245 } 246 247 func setThreadCPUProfiler(hz int32) { 248 setThreadCPUProfilerHz(hz) 249 } 250 251 //go:nosplit 252 func validSIGPROF(mp *m, c *sigctxt) bool { 253 return true 254 } 255 256 func osStackAlloc(s *mspan) { 257 osStackRemap(s, _MAP_STACK) 258 } 259 260 func osStackFree(s *mspan) { 261 // Undo MAP_STACK. 262 osStackRemap(s, 0) 263 } 264 265 func 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 274 func raise(sig uint32) { 275 thrkill(getthrid(), int(sig)) 276 } 277 278 func 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. 284 const sigPerThreadSyscall = 1 << 31 285 286 //go:nosplit 287 func runPerThreadSyscall() { 288 throw("runPerThreadSyscall only valid on linux") 289 }