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