github.com/aloncn/graphics-go@v0.0.1/src/runtime/os1_netbsd.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 const ( 13 _ESRCH = 3 14 _ETIMEDOUT = 60 15 16 // From NetBSD's <sys/time.h> 17 _CLOCK_REALTIME = 0 18 _CLOCK_VIRTUAL = 1 19 _CLOCK_PROF = 2 20 _CLOCK_MONOTONIC = 3 21 ) 22 23 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} 24 25 // From NetBSD'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 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 36 if ret >= 0 { 37 return int32(out) 38 } 39 return 1 40 } 41 42 //go:nosplit 43 func semacreate(mp *m) { 44 } 45 46 //go:nosplit 47 func semasleep(ns int64) int32 { 48 _g_ := getg() 49 50 // Compute sleep deadline. 51 var tsp *timespec 52 if ns >= 0 { 53 var ts timespec 54 var nsec int32 55 ns += nanotime() 56 ts.set_sec(timediv(ns, 1000000000, &nsec)) 57 ts.set_nsec(nsec) 58 tsp = &ts 59 } 60 61 for { 62 v := atomic.Load(&_g_.m.waitsemacount) 63 if v > 0 { 64 if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { 65 return 0 // semaphore acquired 66 } 67 continue 68 } 69 70 // Sleep until unparked by semawakeup or timeout. 71 ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) 72 if ret == _ETIMEDOUT { 73 return -1 74 } 75 } 76 } 77 78 //go:nosplit 79 func semawakeup(mp *m) { 80 atomic.Xadd(&mp.waitsemacount, 1) 81 // From NetBSD's _lwp_unpark(2) manual: 82 // "If the target LWP is not currently waiting, it will return 83 // immediately upon the next call to _lwp_park()." 84 ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) 85 if ret != 0 && ret != _ESRCH { 86 // semawakeup can be called on signal stack. 87 systemstack(func() { 88 print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") 89 }) 90 } 91 } 92 93 // May run with m.p==nil, so write barriers are not allowed. 94 //go:nowritebarrier 95 func newosproc(mp *m, stk unsafe.Pointer) { 96 if false { 97 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n") 98 } 99 100 var uc ucontextt 101 getcontext(unsafe.Pointer(&uc)) 102 103 uc.uc_flags = _UC_SIGMASK | _UC_CPU 104 uc.uc_link = nil 105 uc.uc_sigmask = sigset_all 106 107 lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(netbsdMstart)) 108 109 ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid)) 110 if ret < 0 { 111 print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n") 112 throw("runtime.newosproc") 113 } 114 } 115 116 // netbsdMStart is the function call that starts executing a newly 117 // created thread. On NetBSD, a new thread inherits the signal stack 118 // of the creating thread. That confuses minit, so we remove that 119 // signal stack here before calling the regular mstart. It's a bit 120 // baroque to remove a signal stack here only to add one in minit, but 121 // it's a simple change that keeps NetBSD working like other OS's. 122 // At this point all signals are blocked, so there is no race. 123 //go:nosplit 124 func netbsdMstart() { 125 signalstack(nil) 126 mstart() 127 } 128 129 func osinit() { 130 ncpu = getncpu() 131 } 132 133 var urandom_dev = []byte("/dev/urandom\x00") 134 135 //go:nosplit 136 func getRandomData(r []byte) { 137 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 138 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 139 closefd(fd) 140 extendRandom(r, int(n)) 141 } 142 143 func goenvs() { 144 goenvs_unix() 145 } 146 147 // Called to initialize a new m (including the bootstrap m). 148 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 149 func mpreinit(mp *m) { 150 mp.gsignal = malg(32 * 1024) 151 mp.gsignal.m = mp 152 } 153 154 //go:nosplit 155 func msigsave(mp *m) { 156 sigprocmask(_SIG_SETMASK, nil, &mp.sigmask) 157 } 158 159 //go:nosplit 160 func msigrestore(sigmask sigset) { 161 sigprocmask(_SIG_SETMASK, &sigmask, nil) 162 } 163 164 //go:nosplit 165 func sigblock() { 166 sigprocmask(_SIG_SETMASK, &sigset_all, nil) 167 } 168 169 // Called to initialize a new m (including the bootstrap m). 170 // Called on the new thread, can not allocate memory. 171 func minit() { 172 _g_ := getg() 173 _g_.m.procid = uint64(lwp_self()) 174 175 // Initialize signal handling. 176 177 // On NetBSD a thread created by pthread_create inherits the 178 // signal stack of the creating thread. We always create a 179 // new signal stack here, to avoid having two Go threads using 180 // the same signal stack. This breaks the case of a thread 181 // created in C that calls sigaltstack and then calls a Go 182 // function, because we will lose track of the C code's 183 // sigaltstack, but it's the best we can do. 184 signalstack(&_g_.m.gsignal.stack) 185 _g_.m.newSigstack = true 186 187 // restore signal mask from m.sigmask and unblock essential signals 188 nmask := _g_.m.sigmask 189 for i := range sigtable { 190 if sigtable[i].flags&_SigUnblock != 0 { 191 nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 192 } 193 } 194 sigprocmask(_SIG_SETMASK, &nmask, nil) 195 } 196 197 // Called from dropm to undo the effect of an minit. 198 //go:nosplit 199 func unminit() { 200 if getg().m.newSigstack { 201 signalstack(nil) 202 } 203 } 204 205 func memlimit() uintptr { 206 return 0 207 } 208 209 func sigtramp() 210 211 type sigactiont struct { 212 sa_sigaction uintptr 213 sa_mask sigset 214 sa_flags int32 215 } 216 217 //go:nosplit 218 //go:nowritebarrierrec 219 func setsig(i int32, fn uintptr, restart bool) { 220 var sa sigactiont 221 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 222 if restart { 223 sa.sa_flags |= _SA_RESTART 224 } 225 sa.sa_mask = sigset_all 226 if fn == funcPC(sighandler) { 227 fn = funcPC(sigtramp) 228 } 229 sa.sa_sigaction = fn 230 sigaction(i, &sa, nil) 231 } 232 233 //go:nosplit 234 //go:nowritebarrierrec 235 func setsigstack(i int32) { 236 throw("setsigstack") 237 } 238 239 //go:nosplit 240 //go:nowritebarrierrec 241 func getsig(i int32) uintptr { 242 var sa sigactiont 243 sigaction(i, nil, &sa) 244 if sa.sa_sigaction == funcPC(sigtramp) { 245 return funcPC(sighandler) 246 } 247 return sa.sa_sigaction 248 } 249 250 //go:nosplit 251 func signalstack(s *stack) { 252 var st sigaltstackt 253 if s == nil { 254 st.ss_flags = _SS_DISABLE 255 } else { 256 st.ss_sp = s.lo 257 st.ss_size = s.hi - s.lo 258 st.ss_flags = 0 259 } 260 sigaltstack(&st, nil) 261 } 262 263 //go:nosplit 264 //go:nowritebarrierrec 265 func updatesigmask(m sigmask) { 266 var mask sigset 267 copy(mask.__bits[:], m[:]) 268 sigprocmask(_SIG_SETMASK, &mask, nil) 269 } 270 271 func unblocksig(sig int32) { 272 var mask sigset 273 mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) 274 sigprocmask(_SIG_UNBLOCK, &mask, nil) 275 }