github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/runtime/os_freebsd.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/sys" 9 "unsafe" 10 ) 11 12 type mOS struct{} 13 14 //go:noescape 15 func thr_new(param *thrparam, size int32) int32 16 17 //go:noescape 18 func sigaltstack(new, old *stackt) 19 20 //go:noescape 21 func sigprocmask(how int32, new, old *sigset) 22 23 //go:noescape 24 func setitimer(mode int32, new, old *itimerval) 25 26 //go:noescape 27 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 28 29 func raise(sig uint32) 30 func raiseproc(sig uint32) 31 32 //go:noescape 33 func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32 34 35 func osyield() 36 37 func kqueue() int32 38 39 //go:noescape 40 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 41 func closeonexec(fd int32) 42 43 // From FreeBSD's <sys/sysctl.h> 44 const ( 45 _CTL_HW = 6 46 _HW_PAGESIZE = 7 47 ) 48 49 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}} 50 51 // Undocumented numbers from FreeBSD's lib/libc/gen/sysctlnametomib.c. 52 const ( 53 _CTL_QUERY = 0 54 _CTL_QUERY_MIB = 3 55 ) 56 57 // sysctlnametomib fill mib with dynamically assigned sysctl entries of name, 58 // return count of effected mib slots, return 0 on error. 59 func sysctlnametomib(name []byte, mib *[_CTL_MAXNAME]uint32) uint32 { 60 oid := [2]uint32{_CTL_QUERY, _CTL_QUERY_MIB} 61 miblen := uintptr(_CTL_MAXNAME) 62 if sysctl(&oid[0], 2, (*byte)(unsafe.Pointer(mib)), &miblen, (*byte)(unsafe.Pointer(&name[0])), (uintptr)(len(name))) < 0 { 63 return 0 64 } 65 miblen /= unsafe.Sizeof(uint32(0)) 66 if miblen <= 0 { 67 return 0 68 } 69 return uint32(miblen) 70 } 71 72 const ( 73 _CPU_CURRENT_PID = -1 // Current process ID. 74 ) 75 76 //go:noescape 77 func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32 78 79 //go:systemstack 80 func getncpu() int32 { 81 // Use a large buffer for the CPU mask. We're on the system 82 // stack, so this is fine, and we can't allocate memory for a 83 // dynamically-sized buffer at this point. 84 const maxCPUs = 64 * 1024 85 var mask [maxCPUs / 8]byte 86 var mib [_CTL_MAXNAME]uint32 87 88 // According to FreeBSD's /usr/src/sys/kern/kern_cpuset.c, 89 // cpuset_getaffinity return ERANGE when provided buffer size exceed the limits in kernel. 90 // Querying kern.smp.maxcpus to calculate maximum buffer size. 91 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=200802 92 93 // Variable kern.smp.maxcpus introduced at Dec 23 2003, revision 123766, 94 // with dynamically assigned sysctl entries. 95 miblen := sysctlnametomib([]byte("kern.smp.maxcpus"), &mib) 96 if miblen == 0 { 97 return 1 98 } 99 100 // Query kern.smp.maxcpus. 101 dstsize := uintptr(4) 102 maxcpus := uint32(0) 103 if sysctl(&mib[0], miblen, (*byte)(unsafe.Pointer(&maxcpus)), &dstsize, nil, 0) != 0 { 104 return 1 105 } 106 107 maskSize := int(maxcpus+7) / 8 108 if maskSize < sys.PtrSize { 109 maskSize = sys.PtrSize 110 } 111 if maskSize > len(mask) { 112 maskSize = len(mask) 113 } 114 115 if cpuset_getaffinity(_CPU_LEVEL_WHICH, _CPU_WHICH_PID, _CPU_CURRENT_PID, 116 maskSize, (*byte)(unsafe.Pointer(&mask[0]))) != 0 { 117 return 1 118 } 119 n := int32(0) 120 for _, v := range mask[:maskSize] { 121 for v != 0 { 122 n += int32(v & 1) 123 v >>= 1 124 } 125 } 126 if n == 0 { 127 return 1 128 } 129 return n 130 } 131 132 func getPageSize() uintptr { 133 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} 134 out := uint32(0) 135 nout := unsafe.Sizeof(out) 136 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) 137 if ret >= 0 { 138 return uintptr(out) 139 } 140 return 0 141 } 142 143 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and 144 // thus the code is largely similar. See Linux implementation 145 // and lock_futex.go for comments. 146 147 //go:nosplit 148 func futexsleep(addr *uint32, val uint32, ns int64) { 149 systemstack(func() { 150 futexsleep1(addr, val, ns) 151 }) 152 } 153 154 func futexsleep1(addr *uint32, val uint32, ns int64) { 155 var utp *umtx_time 156 if ns >= 0 { 157 var ut umtx_time 158 ut._clockid = _CLOCK_MONOTONIC 159 ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec))))) 160 utp = &ut 161 } 162 ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp) 163 if ret >= 0 || ret == -_EINTR { 164 return 165 } 166 print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n") 167 *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 168 } 169 170 //go:nosplit 171 func futexwakeup(addr *uint32, cnt uint32) { 172 ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil) 173 if ret >= 0 { 174 return 175 } 176 177 systemstack(func() { 178 print("umtx_wake_addr=", addr, " ret=", ret, "\n") 179 }) 180 } 181 182 func thr_start() 183 184 // May run with m.p==nil, so write barriers are not allowed. 185 //go:nowritebarrier 186 func newosproc(mp *m) { 187 stk := unsafe.Pointer(mp.g0.stack.hi) 188 if false { 189 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n") 190 } 191 192 param := thrparam{ 193 start_func: funcPC(thr_start), 194 arg: unsafe.Pointer(mp), 195 stack_base: mp.g0.stack.lo, 196 stack_size: uintptr(stk) - mp.g0.stack.lo, 197 child_tid: unsafe.Pointer(&mp.procid), 198 parent_tid: nil, 199 tls_base: unsafe.Pointer(&mp.tls[0]), 200 tls_size: unsafe.Sizeof(mp.tls), 201 } 202 203 var oset sigset 204 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 205 // TODO: Check for error. 206 ret := thr_new(¶m, int32(unsafe.Sizeof(param))) 207 sigprocmask(_SIG_SETMASK, &oset, nil) 208 if ret < 0 { 209 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n") 210 throw("newosproc") 211 } 212 } 213 214 // Version of newosproc that doesn't require a valid G. 215 //go:nosplit 216 func newosproc0(stacksize uintptr, fn unsafe.Pointer) { 217 stack := sysAlloc(stacksize, &memstats.stacks_sys) 218 if stack == nil { 219 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack))) 220 exit(1) 221 } 222 // This code "knows" it's being called once from the library 223 // initialization code, and so it's using the static m0 for the 224 // tls and procid (thread) pointers. thr_new() requires the tls 225 // pointers, though the tid pointers can be nil. 226 // However, newosproc0 is currently unreachable because builds 227 // utilizing c-shared/c-archive force external linking. 228 param := thrparam{ 229 start_func: funcPC(fn), 230 arg: nil, 231 stack_base: uintptr(stack), //+stacksize? 232 stack_size: stacksize, 233 child_tid: unsafe.Pointer(&m0.procid), 234 parent_tid: nil, 235 tls_base: unsafe.Pointer(&m0.tls[0]), 236 tls_size: unsafe.Sizeof(m0.tls), 237 } 238 239 var oset sigset 240 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 241 ret := thr_new(¶m, int32(unsafe.Sizeof(param))) 242 sigprocmask(_SIG_SETMASK, &oset, nil) 243 if ret < 0 { 244 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 245 exit(1) 246 } 247 } 248 249 var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n") 250 var failthreadcreate = []byte("runtime: failed to create new OS thread\n") 251 252 // Called to do synchronous initialization of Go code built with 253 // -buildmode=c-archive or -buildmode=c-shared. 254 // None of the Go runtime is initialized. 255 //go:nosplit 256 //go:nowritebarrierrec 257 func libpreinit() { 258 initsig(true) 259 } 260 261 func osinit() { 262 ncpu = getncpu() 263 if physPageSize == 0 { 264 physPageSize = getPageSize() 265 } 266 } 267 268 var urandom_dev = []byte("/dev/urandom\x00") 269 270 //go:nosplit 271 func getRandomData(r []byte) { 272 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 273 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 274 closefd(fd) 275 extendRandom(r, int(n)) 276 } 277 278 func goenvs() { 279 goenvs_unix() 280 } 281 282 // Called to initialize a new m (including the bootstrap m). 283 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 284 func mpreinit(mp *m) { 285 mp.gsignal = malg(32 * 1024) 286 mp.gsignal.m = mp 287 } 288 289 // Called to initialize a new m (including the bootstrap m). 290 // Called on the new thread, cannot allocate memory. 291 func minit() { 292 // m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems. 293 // Fix it up. (Only matters on big-endian, but be clean anyway.) 294 if sys.PtrSize == 4 { 295 _g_ := getg() 296 _g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid))) 297 } 298 299 // On FreeBSD before about April 2017 there was a bug such 300 // that calling execve from a thread other than the main 301 // thread did not reset the signal stack. That would confuse 302 // minitSignals, which calls minitSignalStack, which checks 303 // whether there is currently a signal stack and uses it if 304 // present. To avoid this confusion, explicitly disable the 305 // signal stack on the main thread when not running in a 306 // library. This can be removed when we are confident that all 307 // FreeBSD users are running a patched kernel. See issue #15658. 308 if gp := getg(); !isarchive && !islibrary && gp.m == &m0 && gp == gp.m.g0 { 309 st := stackt{ss_flags: _SS_DISABLE} 310 sigaltstack(&st, nil) 311 } 312 313 minitSignals() 314 } 315 316 // Called from dropm to undo the effect of an minit. 317 //go:nosplit 318 func unminit() { 319 unminitSignals() 320 } 321 322 func sigtramp() 323 324 type sigactiont struct { 325 sa_handler uintptr 326 sa_flags int32 327 sa_mask sigset 328 } 329 330 // See os_freebsd2.go, os_freebsd_amd64.go for setsig function 331 332 //go:nosplit 333 //go:nowritebarrierrec 334 func setsigstack(i uint32) { 335 var sa sigactiont 336 sigaction(i, nil, &sa) 337 if sa.sa_flags&_SA_ONSTACK != 0 { 338 return 339 } 340 sa.sa_flags |= _SA_ONSTACK 341 sigaction(i, &sa, nil) 342 } 343 344 //go:nosplit 345 //go:nowritebarrierrec 346 func getsig(i uint32) uintptr { 347 var sa sigactiont 348 sigaction(i, nil, &sa) 349 return sa.sa_handler 350 } 351 352 // setSignaltstackSP sets the ss_sp field of a stackt. 353 //go:nosplit 354 func setSignalstackSP(s *stackt, sp uintptr) { 355 s.ss_sp = sp 356 } 357 358 //go:nosplit 359 //go:nowritebarrierrec 360 func sigaddset(mask *sigset, i int) { 361 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31) 362 } 363 364 func sigdelset(mask *sigset, i int) { 365 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 366 } 367 368 func (c *sigctxt) fixsigcode(sig uint32) { 369 } 370 371 func sysargs(argc int32, argv **byte) { 372 n := argc + 1 373 374 // skip over argv, envp to get to auxv 375 for argv_index(argv, n) != nil { 376 n++ 377 } 378 379 // skip NULL separator 380 n++ 381 382 // now argv+n is auxv 383 auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) 384 sysauxv(auxv[:]) 385 } 386 387 const ( 388 _AT_NULL = 0 // Terminates the vector 389 _AT_PAGESZ = 6 // Page size in bytes 390 _AT_TIMEKEEP = 22 // Pointer to timehands. 391 _AT_HWCAP = 25 // CPU feature flags 392 _AT_HWCAP2 = 26 // CPU feature flags 2 393 ) 394 395 func sysauxv(auxv []uintptr) { 396 for i := 0; auxv[i] != _AT_NULL; i += 2 { 397 tag, val := auxv[i], auxv[i+1] 398 switch tag { 399 // _AT_NCPUS from auxv shouldn't be used due to golang.org/issue/15206 400 case _AT_PAGESZ: 401 physPageSize = val 402 case _AT_TIMEKEEP: 403 timekeepSharedPage = (*vdsoTimekeep)(unsafe.Pointer(val)) 404 } 405 406 archauxv(tag, val) 407 } 408 } 409 410 // sysSigaction calls the sigaction system call. 411 //go:nosplit 412 func sysSigaction(sig uint32, new, old *sigactiont) { 413 // Use system stack to avoid split stack overflow on amd64 414 if asmSigaction(uintptr(sig), new, old) != 0 { 415 systemstack(func() { 416 throw("sigaction failed") 417 }) 418 } 419 } 420 421 // asmSigaction is implemented in assembly. 422 //go:noescape 423 func asmSigaction(sig uintptr, new, old *sigactiont) int32