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.
16 func thr_new(param *thrparam, size int32) int32
19 func sigaltstack(new, old *stackt)
22 func sigprocmask(how int32, new, old *sigset)
25 func setitimer(mode int32, new, old *itimerval)
28 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
30 func raiseproc(sig uint32)
32 func thr_self() thread
33 func thr_kill(tid thread, sig int)
36 func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
48 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
50 func pipe2(flags int32) (r, w int32, errno int32)
51 func fcntl(fd, cmd, arg int32) (ret int32, errno int32)
53 func issetugid() int32
55 // From FreeBSD's <sys/sysctl.h>
61 var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
63 // Undocumented numbers from FreeBSD's lib/libc/gen/sysctlnametomib.c.
69 // sysctlnametomib fill mib with dynamically assigned sysctl entries of name,
70 // return count of effected mib slots, return 0 on error.
71 func sysctlnametomib(name []byte, mib *[_CTL_MAXNAME]uint32) uint32 {
72 oid := [2]uint32{_CTL_QUERY, _CTL_QUERY_MIB}
73 miblen := uintptr(_CTL_MAXNAME)
74 if sysctl(&oid[0], 2, (*byte)(unsafe.Pointer(mib)), &miblen, (*byte)(unsafe.Pointer(&name[0])), (uintptr)(len(name))) < 0 {
77 miblen /= unsafe.Sizeof(uint32(0))
85 _CPU_CURRENT_PID = -1 // Current process ID.
89 func cpuset_getaffinity(level int, which int, id int64, size int, mask *byte) int32
92 func getncpu() int32 {
93 // Use a large buffer for the CPU mask. We're on the system
94 // stack, so this is fine, and we can't allocate memory for a
95 // dynamically-sized buffer at this point.
96 const maxCPUs = 64 * 1024
97 var mask [maxCPUs / 8]byte
98 var mib [_CTL_MAXNAME]uint32
100 // According to FreeBSD's /usr/src/sys/kern/kern_cpuset.c,
101 // cpuset_getaffinity return ERANGE when provided buffer size exceed the limits in kernel.
102 // Querying kern.smp.maxcpus to calculate maximum buffer size.
103 // See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=200802
105 // Variable kern.smp.maxcpus introduced at Dec 23 2003, revision 123766,
106 // with dynamically assigned sysctl entries.
107 miblen := sysctlnametomib([]byte("kern.smp.maxcpus"), &mib)
112 // Query kern.smp.maxcpus.
113 dstsize := uintptr(4)
115 if sysctl(&mib[0], miblen, (*byte)(unsafe.Pointer(&maxcpus)), &dstsize, nil, 0) != 0 {
119 maskSize := int(maxcpus+7) / 8
120 if maskSize < goarch.PtrSize {
121 maskSize = goarch.PtrSize
123 if maskSize > len(mask) {
127 if cpuset_getaffinity(_CPU_LEVEL_WHICH, _CPU_WHICH_PID, _CPU_CURRENT_PID,
128 maskSize, (*byte)(unsafe.Pointer(&mask[0]))) != 0 {
132 for _, v := range mask[:maskSize] {
144 func getPageSize() uintptr {
145 mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
147 nout := unsafe.Sizeof(out)
148 ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
155 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
156 // thus the code is largely similar. See Linux implementation
157 // and lock_futex.go for comments.
160 func futexsleep(addr *uint32, val uint32, ns int64) {
162 futexsleep1(addr, val, ns)
166 func futexsleep1(addr *uint32, val uint32, ns int64) {
170 ut._clockid = _CLOCK_MONOTONIC
171 ut._timeout.setNsec(ns)
174 ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp)
175 if ret >= 0 || ret == -_EINTR || ret == -_ETIMEDOUT {
178 print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
179 *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
183 func futexwakeup(addr *uint32, cnt uint32) {
184 ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil)
190 print("umtx_wake_addr=", addr, " ret=", ret, "\n")
196 // May run with m.p==nil, so write barriers are not allowed.
199 func newosproc(mp *m) {
200 stk := unsafe.Pointer(mp.g0.stack.hi)
202 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", abi.FuncPCABI0(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
206 start_func: abi.FuncPCABI0(thr_start),
207 arg: unsafe.Pointer(mp),
208 stack_base: mp.g0.stack.lo,
209 stack_size: uintptr(stk) - mp.g0.stack.lo,
210 child_tid: nil, // minit will record tid
212 tls_base: unsafe.Pointer(&mp.tls[0]),
213 tls_size: unsafe.Sizeof(mp.tls),
217 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
218 ret := retryOnEAGAIN(func() int32 {
219 errno := thr_new(¶m, int32(unsafe.Sizeof(param)))
220 // thr_new returns negative errno
223 sigprocmask(_SIG_SETMASK, &oset, nil)
225 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
230 // Version of newosproc that doesn't require a valid G.
233 func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
234 stack := sysAlloc(stacksize, &memstats.stacks_sys)
236 writeErrStr(failallocatestack)
239 // This code "knows" it's being called once from the library
240 // initialization code, and so it's using the static m0 for the
241 // tls and procid (thread) pointers. thr_new() requires the tls
242 // pointers, though the tid pointers can be nil.
243 // However, newosproc0 is currently unreachable because builds
244 // utilizing c-shared/c-archive force external linking.
246 start_func: uintptr(fn),
248 stack_base: uintptr(stack), //+stacksize?
249 stack_size: stacksize,
250 child_tid: nil, // minit will record tid
252 tls_base: unsafe.Pointer(&m0.tls[0]),
253 tls_size: unsafe.Sizeof(m0.tls),
257 sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
258 ret := thr_new(¶m, int32(unsafe.Sizeof(param)))
259 sigprocmask(_SIG_SETMASK, &oset, nil)
261 writeErrStr(failthreadcreate)
266 // Called to do synchronous initialization of Go code built with
267 // -buildmode=c-archive or -buildmode=c-shared.
268 // None of the Go runtime is initialized.
271 //go:nowritebarrierrec
278 if physPageSize == 0 {
279 physPageSize = getPageSize()
283 var urandom_dev = []byte("/dev/urandom\x00")
286 func getRandomData(r []byte) {
287 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
288 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
290 extendRandom(r, int(n))
297 // Called to initialize a new m (including the bootstrap m).
298 // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
299 func mpreinit(mp *m) {
300 mp.gsignal = malg(32 * 1024)
304 // Called to initialize a new m (including the bootstrap m).
305 // Called on the new thread, cannot allocate memory.
307 getg().m.procid = uint64(thr_self())
309 // On FreeBSD before about April 2017 there was a bug such
310 // that calling execve from a thread other than the main
311 // thread did not reset the signal stack. That would confuse
312 // minitSignals, which calls minitSignalStack, which checks
313 // whether there is currently a signal stack and uses it if
314 // present. To avoid this confusion, explicitly disable the
315 // signal stack on the main thread when not running in a
316 // library. This can be removed when we are confident that all
317 // FreeBSD users are running a patched kernel. See issue #15658.
318 if gp := getg(); !isarchive && !islibrary && gp.m == &m0 && gp == gp.m.g0 {
319 st := stackt{ss_flags: _SS_DISABLE}
320 sigaltstack(&st, nil)
326 // Called from dropm to undo the effect of an minit.
334 // Called from exitm, but not from drop, to undo the effect of thread-owned
335 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
336 func mdestroy(mp *m) {
341 type sigactiont struct {
347 // See os_freebsd2.go, os_freebsd_amd64.go for setsig function
350 //go:nowritebarrierrec
351 func setsigstack(i uint32) {
353 sigaction(i, nil, &sa)
354 if sa.sa_flags&_SA_ONSTACK != 0 {
357 sa.sa_flags |= _SA_ONSTACK
358 sigaction(i, &sa, nil)
362 //go:nowritebarrierrec
363 func getsig(i uint32) uintptr {
365 sigaction(i, nil, &sa)
369 // setSignalstackSP sets the ss_sp field of a stackt.
372 func setSignalstackSP(s *stackt, sp uintptr) {
377 //go:nowritebarrierrec
378 func sigaddset(mask *sigset, i int) {
379 mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
382 func sigdelset(mask *sigset, i int) {
383 mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
387 func (c *sigctxt) fixsigcode(sig uint32) {
390 func setProcessCPUProfiler(hz int32) {
391 setProcessCPUProfilerTimer(hz)
394 func setThreadCPUProfiler(hz int32) {
395 setThreadCPUProfilerHz(hz)
399 func validSIGPROF(mp *m, c *sigctxt) bool {
403 func sysargs(argc int32, argv **byte) {
406 // skip over argv, envp to get to auxv
407 for argv_index(argv, n) != nil {
411 // skip NULL separator
414 // now argv+n is auxv
415 auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize))
416 pairs := sysauxv(auxvp[:])
417 auxv = auxvp[: pairs*2 : pairs*2]
421 _AT_NULL = 0 // Terminates the vector
422 _AT_PAGESZ = 6 // Page size in bytes
423 _AT_PLATFORM = 15 // string identifying platform
424 _AT_TIMEKEEP = 22 // Pointer to timehands.
425 _AT_HWCAP = 25 // CPU feature flags
426 _AT_HWCAP2 = 26 // CPU feature flags 2
429 func sysauxv(auxv []uintptr) (pairs int) {
431 for i = 0; auxv[i] != _AT_NULL; i += 2 {
432 tag, val := auxv[i], auxv[i+1]
434 // _AT_NCPUS from auxv shouldn't be used due to golang.org/issue/15206
438 timekeepSharedPage = (*vdsoTimekeep)(unsafe.Pointer(val))
446 // sysSigaction calls the sigaction system call.
449 func sysSigaction(sig uint32, new, old *sigactiont) {
450 // Use system stack to avoid split stack overflow on amd64
451 if asmSigaction(uintptr(sig), new, old) != 0 {
453 throw("sigaction failed")
458 // asmSigaction is implemented in assembly.
461 func asmSigaction(sig uintptr, new, old *sigactiont) int32
463 // raise sends a signal to the calling thread.
465 // It must be nosplit because it is used by the signal handler before
466 // it definitely has a Go stack.
469 func raise(sig uint32) {
470 thr_kill(thr_self(), int(sig))
473 func signalM(mp *m, sig int) {
474 thr_kill(thread(mp.procid), sig)
477 // sigPerThreadSyscall is only used on linux, so we assign a bogus signal
479 const sigPerThreadSyscall = 1 << 31
482 func runPerThreadSyscall() {
483 throw("runPerThreadSyscall only valid on linux")