github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/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 //go:noescape 17 func setitimer(mode int32, new, old *itimerval) 18 19 //go:noescape 20 func sigaction(sig uint32, new, old *sigactiont) 21 22 //go:noescape 23 func sigaltstack(new, old *stackt) 24 25 //go:noescape 26 func obsdsigprocmask(how int32, new sigset) sigset 27 28 //go:nosplit 29 //go:nowritebarrierrec 30 func sigprocmask(how int32, new, old *sigset) { 31 n := sigset(0) 32 if new != nil { 33 n = *new 34 } 35 r := obsdsigprocmask(how, n) 36 if old != nil { 37 *old = r 38 } 39 } 40 41 //go:noescape 42 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 43 44 func raise(sig uint32) 45 func raiseproc(sig uint32) 46 47 //go:noescape 48 func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32 49 50 //go:noescape 51 func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32 52 53 //go:noescape 54 func thrwakeup(ident uintptr, n int32) int32 55 56 func osyield() 57 58 const ( 59 _ESRCH = 3 60 _EAGAIN = 35 61 _EWOULDBLOCK = _EAGAIN 62 _ENOTSUP = 91 63 64 // From OpenBSD's sys/time.h 65 _CLOCK_REALTIME = 0 66 _CLOCK_VIRTUAL = 1 67 _CLOCK_PROF = 2 68 _CLOCK_MONOTONIC = 3 69 ) 70 71 type sigset uint32 72 73 var sigset_all = ^sigset(0) 74 75 // From OpenBSD's <sys/sysctl.h> 76 const ( 77 _CTL_HW = 6 78 _HW_NCPU = 3 79 _HW_PAGESIZE = 7 80 ) 81 82 func getncpu() int32 { 83 mib := [2]uint32{_CTL_HW, _HW_NCPU} 84 out := uint32(0) 85 nout := unsafe.Sizeof(out) 86 87 // Fetch hw.ncpu via sysctl. 88 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 89 if ret >= 0 { 90 return int32(out) 91 } 92 return 1 93 } 94 95 func getPageSize() uintptr { 96 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} 97 out := uint32(0) 98 nout := unsafe.Sizeof(out) 99 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 100 if ret >= 0 { 101 return uintptr(out) 102 } 103 return 0 104 } 105 106 //go:nosplit 107 func semacreate(mp *m) { 108 } 109 110 //go:nosplit 111 func semasleep(ns int64) int32 { 112 _g_ := getg() 113 114 // Compute sleep deadline. 115 var tsp *timespec 116 if ns >= 0 { 117 var ts timespec 118 var nsec int32 119 ns += nanotime() 120 ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) 121 ts.set_nsec(nsec) 122 tsp = &ts 123 } 124 125 for { 126 v := atomic.Load(&_g_.m.waitsemacount) 127 if v > 0 { 128 if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { 129 return 0 // semaphore acquired 130 } 131 continue 132 } 133 134 // Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0. 135 // 136 // From OpenBSD's __thrsleep(2) manual: 137 // "The abort argument, if not NULL, points to an int that will 138 // be examined [...] immediately before blocking. If that int 139 // is non-zero then __thrsleep() will immediately return EINTR 140 // without blocking." 141 ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount) 142 if ret == _EWOULDBLOCK { 143 return -1 144 } 145 } 146 } 147 148 //go:nosplit 149 func semawakeup(mp *m) { 150 atomic.Xadd(&mp.waitsemacount, 1) 151 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) 152 if ret != 0 && ret != _ESRCH { 153 // semawakeup can be called on signal stack. 154 systemstack(func() { 155 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 156 }) 157 } 158 } 159 160 // May run with m.p==nil, so write barriers are not allowed. 161 //go:nowritebarrier 162 func newosproc(mp *m, stk unsafe.Pointer) { 163 if false { 164 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 165 } 166 167 param := tforkt{ 168 tf_tcb: unsafe.Pointer(&mp.tls[0]), 169 tf_tid: (*int32)(unsafe.Pointer(&mp.procid)), 170 tf_stack: uintptr(stk), 171 } 172 173 var oset sigset 174 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 175 ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) 176 sigprocmask(_SIG_SETMASK, &oset, nil) 177 178 if ret < 0 { 179 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 180 if ret == -_EAGAIN { 181 println("runtime: may need to increase max user processes (ulimit -p)") 182 } 183 throw("runtime.newosproc") 184 } 185 } 186 187 func osinit() { 188 ncpu = getncpu() 189 physPageSize = getPageSize() 190 } 191 192 var urandom_dev = []byte("/dev/urandom\x00") 193 194 //go:nosplit 195 func getRandomData(r []byte) { 196 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 197 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 198 closefd(fd) 199 extendRandom(r, int(n)) 200 } 201 202 func goenvs() { 203 goenvs_unix() 204 } 205 206 // Called to initialize a new m (including the bootstrap m). 207 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 208 func mpreinit(mp *m) { 209 mp.gsignal = malg(32 * 1024) 210 mp.gsignal.m = mp 211 } 212 213 // Called to initialize a new m (including the bootstrap m). 214 // Called on the new thread, can not allocate memory. 215 func minit() { 216 // m.procid is a uint64, but tfork writes an int32. Fix it up. 217 _g_ := getg() 218 _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) 219 220 minitSignals() 221 } 222 223 // Called from dropm to undo the effect of an minit. 224 //go:nosplit 225 func unminit() { 226 unminitSignals() 227 } 228 229 func memlimit() uintptr { 230 return 0 231 } 232 233 func sigtramp() 234 235 type sigactiont struct { 236 sa_sigaction uintptr 237 sa_mask uint32 238 sa_flags int32 239 } 240 241 //go:nosplit 242 //go:nowritebarrierrec 243 func setsig(i uint32, fn uintptr) { 244 var sa sigactiont 245 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 246 sa.sa_mask = uint32(sigset_all) 247 if fn == funcPC(sighandler) { 248 fn = funcPC(sigtramp) 249 } 250 sa.sa_sigaction = fn 251 sigaction(i, &sa, nil) 252 } 253 254 //go:nosplit 255 //go:nowritebarrierrec 256 func setsigstack(i uint32) { 257 throw("setsigstack") 258 } 259 260 //go:nosplit 261 //go:nowritebarrierrec 262 func getsig(i uint32) uintptr { 263 var sa sigactiont 264 sigaction(i, nil, &sa) 265 return sa.sa_sigaction 266 } 267 268 // setSignaltstackSP sets the ss_sp field of a stackt. 269 //go:nosplit 270 func setSignalstackSP(s *stackt, sp uintptr) { 271 s.ss_sp = sp 272 } 273 274 //go:nosplit 275 //go:nowritebarrierrec 276 func sigaddset(mask *sigset, i int) { 277 *mask |= 1 << (uint32(i) - 1) 278 } 279 280 func sigdelset(mask *sigset, i int) { 281 *mask &^= 1 << (uint32(i) - 1) 282 } 283 284 func (c *sigctxt) fixsigcode(sig uint32) { 285 }