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 // From FreeBSD's <sys/sysctl.h> 10 const ( 11 _CTL_HW = 6 12 _HW_NCPU = 3 13 ) 14 15 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} 16 17 func getncpu() int32 { 18 mib := [2]uint32{_CTL_HW, _HW_NCPU} 19 out := uint32(0) 20 nout := unsafe.Sizeof(out) 21 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 22 if ret >= 0 { 23 return int32(out) 24 } 25 return 1 26 } 27 28 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and 29 // thus the code is largely similar. See Linux implementation 30 // and lock_futex.go for comments. 31 32 //go:nosplit 33 func futexsleep(addr *uint32, val uint32, ns int64) { 34 systemstack(func() { 35 futexsleep1(addr, val, ns) 36 }) 37 } 38 39 func futexsleep1(addr *uint32, val uint32, ns int64) { 40 var tsp *timespec 41 if ns >= 0 { 42 var ts timespec 43 ts.tv_nsec = 0 44 ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec))))) 45 tsp = &ts 46 } 47 ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp) 48 if ret >= 0 || ret == -_EINTR { 49 return 50 } 51 print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n") 52 *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 53 } 54 55 //go:nosplit 56 func futexwakeup(addr *uint32, cnt uint32) { 57 ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil) 58 if ret >= 0 { 59 return 60 } 61 62 systemstack(func() { 63 print("umtx_wake_addr=", addr, " ret=", ret, "\n") 64 }) 65 } 66 67 func thr_start() 68 69 // May run with m.p==nil, so write barriers are not allowed. 70 //go:nowritebarrier 71 func newosproc(mp *m, stk unsafe.Pointer) { 72 if false { 73 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n") 74 } 75 76 // NOTE(rsc): This code is confused. stackbase is the top of the stack 77 // and is equal to stk. However, it's working, so I'm not changing it. 78 param := thrparam{ 79 start_func: funcPC(thr_start), 80 arg: unsafe.Pointer(mp), 81 stack_base: mp.g0.stack.hi, 82 stack_size: uintptr(stk) - mp.g0.stack.hi, 83 child_tid: unsafe.Pointer(&mp.procid), 84 parent_tid: nil, 85 tls_base: unsafe.Pointer(&mp.tls[0]), 86 tls_size: unsafe.Sizeof(mp.tls), 87 } 88 mp.tls[0] = uintptr(mp.id) // so 386 asm can find it 89 90 var oset sigset 91 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 92 thr_new(¶m, int32(unsafe.Sizeof(param))) 93 sigprocmask(_SIG_SETMASK, &oset, nil) 94 } 95 96 func osinit() { 97 ncpu = getncpu() 98 } 99 100 var urandom_dev = []byte("/dev/urandom\x00") 101 102 //go:nosplit 103 func getRandomData(r []byte) { 104 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 105 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 106 closefd(fd) 107 extendRandom(r, int(n)) 108 } 109 110 func goenvs() { 111 goenvs_unix() 112 } 113 114 // Called to initialize a new m (including the bootstrap m). 115 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 116 func mpreinit(mp *m) { 117 mp.gsignal = malg(32 * 1024) 118 mp.gsignal.m = mp 119 } 120 121 func msigsave(mp *m) { 122 smask := (*sigset)(unsafe.Pointer(&mp.sigmask)) 123 if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) { 124 throw("insufficient storage for signal mask") 125 } 126 sigprocmask(_SIG_SETMASK, nil, smask) 127 } 128 129 // Called to initialize a new m (including the bootstrap m). 130 // Called on the new thread, can not allocate memory. 131 func minit() { 132 _g_ := getg() 133 134 // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems. 135 // Fix it up. (Only matters on big-endian, but be clean anyway.) 136 if ptrSize == 4 { 137 _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid))) 138 } 139 140 // Initialize signal handling. 141 signalstack(&_g_.m.gsignal.stack) 142 143 // restore signal mask from m.sigmask and unblock essential signals 144 nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask)) 145 for i := range sigtable { 146 if sigtable[i].flags&_SigUnblock != 0 { 147 nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 148 } 149 } 150 sigprocmask(_SIG_SETMASK, &nmask, nil) 151 } 152 153 // Called from dropm to undo the effect of an minit. 154 func unminit() { 155 _g_ := getg() 156 smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask)) 157 sigprocmask(_SIG_SETMASK, smask, nil) 158 signalstack(nil) 159 } 160 161 func memlimit() uintptr { 162 /* 163 TODO: Convert to Go when something actually uses the result. 164 Rlimit rl; 165 extern byte runtimetext[], runtimeend[]; 166 uintptr used; 167 168 if(runtimegetrlimit(RLIMIT_AS, &rl) != 0) 169 return 0; 170 if(rl.rlim_cur >= 0x7fffffff) 171 return 0; 172 173 // Estimate our VM footprint excluding the heap. 174 // Not an exact science: use size of binary plus 175 // some room for thread stacks. 176 used = runtimeend - runtimetext + (64<<20); 177 if(used >= rl.rlim_cur) 178 return 0; 179 180 // If there's not at least 16 MB left, we're probably 181 // not going to be able to do much. Treat as no limit. 182 rl.rlim_cur -= used; 183 if(rl.rlim_cur < (16<<20)) 184 return 0; 185 186 return rl.rlim_cur - used; 187 */ 188 189 return 0 190 } 191 192 func sigtramp() 193 194 type sigactiont struct { 195 sa_handler uintptr 196 sa_flags int32 197 sa_mask sigset 198 } 199 200 func setsig(i int32, fn uintptr, restart bool) { 201 var sa sigactiont 202 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK 203 if restart { 204 sa.sa_flags |= _SA_RESTART 205 } 206 sa.sa_mask = sigset_all 207 if fn == funcPC(sighandler) { 208 fn = funcPC(sigtramp) 209 } 210 sa.sa_handler = fn 211 sigaction(i, &sa, nil) 212 } 213 214 func setsigstack(i int32) { 215 throw("setsigstack") 216 } 217 218 func getsig(i int32) uintptr { 219 var sa sigactiont 220 sigaction(i, nil, &sa) 221 if sa.sa_handler == funcPC(sigtramp) { 222 return funcPC(sighandler) 223 } 224 return sa.sa_handler 225 } 226 227 func signalstack(s *stack) { 228 var st stackt 229 if s == nil { 230 st.ss_flags = _SS_DISABLE 231 } else { 232 st.ss_sp = s.lo 233 st.ss_size = s.hi - s.lo 234 st.ss_flags = 0 235 } 236 sigaltstack(&st, nil) 237 } 238 239 func updatesigmask(m [(_NSIG + 31) / 32]uint32) { 240 var mask sigset 241 copy(mask.__bits[:], m[:]) 242 sigprocmask(_SIG_SETMASK, &mask, nil) 243 } 244 245 func unblocksig(sig int32) { 246 var mask sigset 247 mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31) 248 sigprocmask(_SIG_UNBLOCK, &mask, nil) 249 } 250