github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/src/runtime/os1_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 "unsafe" 8 9 const ( 10 ESRCH = 3 11 EAGAIN = 35 12 EWOULDBLOCK = EAGAIN 13 ENOTSUP = 91 14 15 // From OpenBSD's sys/time.h 16 CLOCK_REALTIME = 0 17 CLOCK_VIRTUAL = 1 18 CLOCK_PROF = 2 19 CLOCK_MONOTONIC = 3 20 ) 21 22 var sigset_none = uint32(0) 23 var sigset_all = ^sigset_none 24 25 // From OpenBSD's <sys/sysctl.h> 26 const ( 27 CTL_HW = 6 28 HW_NCPU = 3 29 ) 30 31 func getncpu() int32 { 32 mib := [2]uint32{CTL_HW, HW_NCPU} 33 out := uint32(0) 34 nout := unsafe.Sizeof(out) 35 36 // Fetch hw.ncpu via sysctl. 37 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 38 if ret >= 0 { 39 return int32(out) 40 } 41 return 1 42 } 43 44 //go:nosplit 45 func semacreate() uintptr { 46 return 1 47 } 48 49 //go:nosplit 50 func semasleep(ns int64) int32 { 51 _g_ := getg() 52 53 // Compute sleep deadline. 54 var tsp *timespec 55 if ns >= 0 { 56 var ts timespec 57 var nsec int32 58 ns += nanotime() 59 ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) 60 ts.set_nsec(nsec) 61 tsp = &ts 62 } 63 64 for { 65 // spin-mutex lock 66 for { 67 if xchg(&_g_.m.waitsemalock, 1) == 0 { 68 break 69 } 70 osyield() 71 } 72 73 if _g_.m.waitsemacount != 0 { 74 // semaphore is available. 75 _g_.m.waitsemacount-- 76 // spin-mutex unlock 77 atomicstore(&_g_.m.waitsemalock, 0) 78 return 0 // semaphore acquired 79 } 80 81 // sleep until semaphore != 0 or timeout. 82 // thrsleep unlocks m.waitsemalock. 83 ret := thrsleep((uintptr)(unsafe.Pointer(&_g_.m.waitsemacount)), CLOCK_MONOTONIC, tsp, (uintptr)(unsafe.Pointer(&_g_.m.waitsemalock)), (*int32)(unsafe.Pointer(&_g_.m.waitsemacount))) 84 if ret == EWOULDBLOCK { 85 return -1 86 } 87 } 88 } 89 90 //go:nosplit 91 func semawakeup(mp *m) { 92 // spin-mutex lock 93 for { 94 if xchg(&mp.waitsemalock, 1) == 0 { 95 break 96 } 97 osyield() 98 } 99 mp.waitsemacount++ 100 ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1) 101 if ret != 0 && ret != ESRCH { 102 // semawakeup can be called on signal stack. 103 systemstack(func() { 104 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 105 }) 106 } 107 // spin-mutex unlock 108 atomicstore(&mp.waitsemalock, 0) 109 } 110 111 func newosproc(mp *m, stk unsafe.Pointer) { 112 if false { 113 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n") 114 } 115 116 mp.tls[0] = uintptr(mp.id) // so 386 asm can find it 117 118 param := tforkt{ 119 tf_tcb: unsafe.Pointer(&mp.tls[0]), 120 tf_tid: (*int32)(unsafe.Pointer(&mp.procid)), 121 tf_stack: uintptr(stk), 122 } 123 124 oset := sigprocmask(_SIG_SETMASK, sigset_all) 125 ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart)) 126 sigprocmask(_SIG_SETMASK, oset) 127 128 if ret < 0 { 129 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 130 if ret == -ENOTSUP { 131 print("runtime: is kern.rthreads disabled?\n") 132 } 133 throw("runtime.newosproc") 134 } 135 } 136 137 func osinit() { 138 ncpu = getncpu() 139 } 140 141 var urandom_dev = []byte("/dev/urandom\x00") 142 143 //go:nosplit 144 func getRandomData(r []byte) { 145 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 146 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 147 close(fd) 148 extendRandom(r, int(n)) 149 } 150 151 func goenvs() { 152 goenvs_unix() 153 } 154 155 // Called to initialize a new m (including the bootstrap m). 156 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 157 func mpreinit(mp *m) { 158 mp.gsignal = malg(32 * 1024) 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 _g_ := getg() 166 167 // m.procid is a uint64, but tfork writes an int32. Fix it up. 168 _g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid))) 169 170 // Initialize signal handling 171 signalstack((*byte)(unsafe.Pointer(_g_.m.gsignal.stack.lo)), 32*1024) 172 sigprocmask(_SIG_SETMASK, sigset_none) 173 } 174 175 // Called from dropm to undo the effect of an minit. 176 func unminit() { 177 signalstack(nil, 0) 178 } 179 180 func memlimit() uintptr { 181 return 0 182 } 183 184 func sigtramp() 185 186 type sigactiont struct { 187 sa_sigaction uintptr 188 sa_mask uint32 189 sa_flags int32 190 } 191 192 func setsig(i int32, fn uintptr, restart bool) { 193 var sa sigactiont 194 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 195 if restart { 196 sa.sa_flags |= _SA_RESTART 197 } 198 sa.sa_mask = sigset_all 199 if fn == funcPC(sighandler) { 200 fn = funcPC(sigtramp) 201 } 202 sa.sa_sigaction = fn 203 sigaction(i, &sa, nil) 204 } 205 206 func setsigstack(i int32) { 207 throw("setsigstack") 208 } 209 210 func getsig(i int32) uintptr { 211 var sa sigactiont 212 sigaction(i, nil, &sa) 213 if sa.sa_sigaction == funcPC(sigtramp) { 214 return funcPC(sighandler) 215 } 216 return sa.sa_sigaction 217 } 218 219 func signalstack(p *byte, n int32) { 220 var st stackt 221 222 st.ss_sp = uintptr(unsafe.Pointer(p)) 223 st.ss_size = uintptr(n) 224 st.ss_flags = 0 225 if p == nil { 226 st.ss_flags = _SS_DISABLE 227 } 228 sigaltstack(&st, nil) 229 } 230 231 func unblocksignals() { 232 sigprocmask(_SIG_SETMASK, sigset_none) 233 }