Dan Willemsen | 0c15709 | 2016-07-08 13:57:52 -0700 | [diff] [blame^] | 1 | // Copyright 2011 The Go Authors. All rights reserved. |
Colin Cross | 7bb052a | 2015-02-03 12:59:37 -0800 | [diff] [blame] | 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 | |
Dan Willemsen | 0c15709 | 2016-07-08 13:57:52 -0700 | [diff] [blame^] | 7 | import ( |
| 8 | "runtime/internal/sys" |
| 9 | "unsafe" |
| 10 | ) |
| 11 | |
| 12 | type mOS struct{} |
Colin Cross | 7bb052a | 2015-02-03 12:59:37 -0800 | [diff] [blame] | 13 | |
Dan Willemsen | 6ff2325 | 2015-09-15 13:49:18 -0700 | [diff] [blame] | 14 | //go:noescape |
| 15 | func thr_new(param *thrparam, size int32) |
| 16 | |
| 17 | //go:noescape |
| 18 | func sigaltstack(new, old *stackt) |
| 19 | |
| 20 | //go:noescape |
Dan Willemsen | 6ff2325 | 2015-09-15 13:49:18 -0700 | [diff] [blame] | 21 | func sigaction(sig int32, new, old *sigactiont) |
| 22 | |
| 23 | //go:noescape |
| 24 | func sigprocmask(how int32, new, old *sigset) |
| 25 | |
| 26 | //go:noescape |
| 27 | func setitimer(mode int32, new, old *itimerval) |
| 28 | |
| 29 | //go:noescape |
Colin Cross | 7bb052a | 2015-02-03 12:59:37 -0800 | [diff] [blame] | 30 | func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 |
Dan Willemsen | 6ff2325 | 2015-09-15 13:49:18 -0700 | [diff] [blame] | 31 | |
| 32 | //go:noescape |
Colin Cross | 7bb052a | 2015-02-03 12:59:37 -0800 | [diff] [blame] | 33 | func getrlimit(kind int32, limit unsafe.Pointer) int32 |
| 34 | func raise(sig int32) |
Dan Willemsen | 6ff2325 | 2015-09-15 13:49:18 -0700 | [diff] [blame] | 35 | func raiseproc(sig int32) |
| 36 | |
| 37 | //go:noescape |
| 38 | func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32 |
| 39 | |
| 40 | func osyield() |
Dan Willemsen | 0c15709 | 2016-07-08 13:57:52 -0700 | [diff] [blame^] | 41 | |
| 42 | // From FreeBSD's <sys/sysctl.h> |
| 43 | const ( |
| 44 | _CTL_HW = 6 |
| 45 | _HW_NCPU = 3 |
| 46 | ) |
| 47 | |
| 48 | var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} |
| 49 | |
| 50 | func getncpu() int32 { |
| 51 | mib := [2]uint32{_CTL_HW, _HW_NCPU} |
| 52 | out := uint32(0) |
| 53 | nout := unsafe.Sizeof(out) |
| 54 | ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) |
| 55 | if ret >= 0 { |
| 56 | return int32(out) |
| 57 | } |
| 58 | return 1 |
| 59 | } |
| 60 | |
| 61 | // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and |
| 62 | // thus the code is largely similar. See Linux implementation |
| 63 | // and lock_futex.go for comments. |
| 64 | |
| 65 | //go:nosplit |
| 66 | func futexsleep(addr *uint32, val uint32, ns int64) { |
| 67 | systemstack(func() { |
| 68 | futexsleep1(addr, val, ns) |
| 69 | }) |
| 70 | } |
| 71 | |
| 72 | func futexsleep1(addr *uint32, val uint32, ns int64) { |
| 73 | var tsp *timespec |
| 74 | if ns >= 0 { |
| 75 | var ts timespec |
| 76 | ts.tv_nsec = 0 |
| 77 | ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec))))) |
| 78 | tsp = &ts |
| 79 | } |
| 80 | ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp) |
| 81 | if ret >= 0 || ret == -_EINTR { |
| 82 | return |
| 83 | } |
| 84 | print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n") |
| 85 | *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 |
| 86 | } |
| 87 | |
| 88 | //go:nosplit |
| 89 | func futexwakeup(addr *uint32, cnt uint32) { |
| 90 | ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil) |
| 91 | if ret >= 0 { |
| 92 | return |
| 93 | } |
| 94 | |
| 95 | systemstack(func() { |
| 96 | print("umtx_wake_addr=", addr, " ret=", ret, "\n") |
| 97 | }) |
| 98 | } |
| 99 | |
| 100 | func thr_start() |
| 101 | |
| 102 | // May run with m.p==nil, so write barriers are not allowed. |
| 103 | //go:nowritebarrier |
| 104 | func newosproc(mp *m, stk unsafe.Pointer) { |
| 105 | if false { |
| 106 | print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n") |
| 107 | } |
| 108 | |
| 109 | // NOTE(rsc): This code is confused. stackbase is the top of the stack |
| 110 | // and is equal to stk. However, it's working, so I'm not changing it. |
| 111 | param := thrparam{ |
| 112 | start_func: funcPC(thr_start), |
| 113 | arg: unsafe.Pointer(mp), |
| 114 | stack_base: mp.g0.stack.hi, |
| 115 | stack_size: uintptr(stk) - mp.g0.stack.hi, |
| 116 | child_tid: unsafe.Pointer(&mp.procid), |
| 117 | parent_tid: nil, |
| 118 | tls_base: unsafe.Pointer(&mp.tls[0]), |
| 119 | tls_size: unsafe.Sizeof(mp.tls), |
| 120 | } |
| 121 | |
| 122 | var oset sigset |
| 123 | sigprocmask(_SIG_SETMASK, &sigset_all, &oset) |
| 124 | // TODO: Check for error. |
| 125 | thr_new(¶m, int32(unsafe.Sizeof(param))) |
| 126 | sigprocmask(_SIG_SETMASK, &oset, nil) |
| 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, cannot allocate memory. |
| 171 | func minit() { |
| 172 | _g_ := getg() |
| 173 | |
| 174 | // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems. |
| 175 | // Fix it up. (Only matters on big-endian, but be clean anyway.) |
| 176 | if sys.PtrSize == 4 { |
| 177 | _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid))) |
| 178 | } |
| 179 | |
| 180 | // Initialize signal handling. |
| 181 | var st stackt |
| 182 | sigaltstack(nil, &st) |
| 183 | if st.ss_flags&_SS_DISABLE != 0 { |
| 184 | signalstack(&_g_.m.gsignal.stack) |
| 185 | _g_.m.newSigstack = true |
| 186 | } else { |
| 187 | // Use existing signal stack. |
| 188 | stsp := uintptr(unsafe.Pointer(st.ss_sp)) |
| 189 | _g_.m.gsignal.stack.lo = stsp |
| 190 | _g_.m.gsignal.stack.hi = stsp + st.ss_size |
| 191 | _g_.m.gsignal.stackguard0 = stsp + _StackGuard |
| 192 | _g_.m.gsignal.stackguard1 = stsp + _StackGuard |
| 193 | _g_.m.gsignal.stackAlloc = st.ss_size |
| 194 | _g_.m.newSigstack = false |
| 195 | } |
| 196 | |
| 197 | // restore signal mask from m.sigmask and unblock essential signals |
| 198 | nmask := _g_.m.sigmask |
| 199 | for i := range sigtable { |
| 200 | if sigtable[i].flags&_SigUnblock != 0 { |
| 201 | nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) |
| 202 | } |
| 203 | } |
| 204 | sigprocmask(_SIG_SETMASK, &nmask, nil) |
| 205 | } |
| 206 | |
| 207 | // Called from dropm to undo the effect of an minit. |
| 208 | //go:nosplit |
| 209 | func unminit() { |
| 210 | if getg().m.newSigstack { |
| 211 | signalstack(nil) |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | func memlimit() uintptr { |
| 216 | /* |
| 217 | TODO: Convert to Go when something actually uses the result. |
| 218 | Rlimit rl; |
| 219 | extern byte runtime·text[], runtime·end[]; |
| 220 | uintptr used; |
| 221 | |
| 222 | if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) |
| 223 | return 0; |
| 224 | if(rl.rlim_cur >= 0x7fffffff) |
| 225 | return 0; |
| 226 | |
| 227 | // Estimate our VM footprint excluding the heap. |
| 228 | // Not an exact science: use size of binary plus |
| 229 | // some room for thread stacks. |
| 230 | used = runtime·end - runtime·text + (64<<20); |
| 231 | if(used >= rl.rlim_cur) |
| 232 | return 0; |
| 233 | |
| 234 | // If there's not at least 16 MB left, we're probably |
| 235 | // not going to be able to do much. Treat as no limit. |
| 236 | rl.rlim_cur -= used; |
| 237 | if(rl.rlim_cur < (16<<20)) |
| 238 | return 0; |
| 239 | |
| 240 | return rl.rlim_cur - used; |
| 241 | */ |
| 242 | |
| 243 | return 0 |
| 244 | } |
| 245 | |
| 246 | func sigtramp() |
| 247 | |
| 248 | type sigactiont struct { |
| 249 | sa_handler uintptr |
| 250 | sa_flags int32 |
| 251 | sa_mask sigset |
| 252 | } |
| 253 | |
| 254 | //go:nosplit |
| 255 | //go:nowritebarrierrec |
| 256 | func setsig(i int32, fn uintptr, restart bool) { |
| 257 | var sa sigactiont |
| 258 | sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK |
| 259 | if restart { |
| 260 | sa.sa_flags |= _SA_RESTART |
| 261 | } |
| 262 | sa.sa_mask = sigset_all |
| 263 | if fn == funcPC(sighandler) { |
| 264 | fn = funcPC(sigtramp) |
| 265 | } |
| 266 | sa.sa_handler = fn |
| 267 | sigaction(i, &sa, nil) |
| 268 | } |
| 269 | |
| 270 | //go:nosplit |
| 271 | //go:nowritebarrierrec |
| 272 | func setsigstack(i int32) { |
| 273 | throw("setsigstack") |
| 274 | } |
| 275 | |
| 276 | //go:nosplit |
| 277 | //go:nowritebarrierrec |
| 278 | func getsig(i int32) uintptr { |
| 279 | var sa sigactiont |
| 280 | sigaction(i, nil, &sa) |
| 281 | if sa.sa_handler == funcPC(sigtramp) { |
| 282 | return funcPC(sighandler) |
| 283 | } |
| 284 | return sa.sa_handler |
| 285 | } |
| 286 | |
| 287 | //go:nosplit |
| 288 | func signalstack(s *stack) { |
| 289 | var st stackt |
| 290 | if s == nil { |
| 291 | st.ss_flags = _SS_DISABLE |
| 292 | } else { |
| 293 | st.ss_sp = s.lo |
| 294 | st.ss_size = s.hi - s.lo |
| 295 | st.ss_flags = 0 |
| 296 | } |
| 297 | sigaltstack(&st, nil) |
| 298 | } |
| 299 | |
| 300 | //go:nosplit |
| 301 | //go:nowritebarrierrec |
| 302 | func updatesigmask(m [(_NSIG + 31) / 32]uint32) { |
| 303 | var mask sigset |
| 304 | copy(mask.__bits[:], m[:]) |
| 305 | sigprocmask(_SIG_SETMASK, &mask, nil) |
| 306 | } |
| 307 | |
| 308 | func unblocksig(sig int32) { |
| 309 | var mask sigset |
| 310 | mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) |
| 311 | sigprocmask(_SIG_UNBLOCK, &mask, nil) |
| 312 | } |