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