|  | // Copyright 2011 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package runtime | 
|  |  | 
|  | import ( | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | type mOS struct{} | 
|  |  | 
|  | //go:noescape | 
|  | //extern _umtx_op | 
|  | func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uinptr, ts *umtx_time) int32 | 
|  |  | 
|  | func getPageSize() uintptr { | 
|  | mib := [2]uint32{_CTL_HW, _HW_PAGESIZE} | 
|  | out := uint32(0) | 
|  | nout := unsafe.Sizeof(out) | 
|  | ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0) | 
|  | if ret >= 0 { | 
|  | return uintptr(out) | 
|  | } | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and | 
|  | // thus the code is largely similar. See Linux implementation | 
|  | // and lock_futex.go for comments. | 
|  |  | 
|  | //go:nosplit | 
|  | func futexsleep(addr *uint32, val uint32, ns int64) { | 
|  | systemstack(func() { | 
|  | futexsleep1(addr, val, ns) | 
|  | }) | 
|  | } | 
|  |  | 
|  | func futexsleep1(addr *uint32, val uint32, ns int64) { | 
|  | var utp *umtx_time | 
|  | if ns >= 0 { | 
|  | var ut umtx_time | 
|  | ut._clockid = _CLOCK_MONOTONIC | 
|  | ut._timeout.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ut._timeout.tv_nsec))))) | 
|  | utp = &ut | 
|  | } | 
|  | ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, unsafe.Sizeof(*utp), utp) | 
|  | if ret >= 0 || ret == -_EINTR { | 
|  | return | 
|  | } | 
|  | print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n") | 
|  | *(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005 | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | func futexwakeup(addr *uint32, cnt uint32) { | 
|  | ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, 0, nil) | 
|  | if ret >= 0 { | 
|  | return | 
|  | } | 
|  |  | 
|  | systemstack(func() { | 
|  | print("umtx_wake_addr=", addr, " ret=", ret, "\n") | 
|  | }) | 
|  | } | 
|  |  | 
|  | func sysargs(argc int32, argv **byte) { | 
|  | n := argc + 1 | 
|  |  | 
|  | // skip over argv, envp to get to auxv | 
|  | for argv_index(argv, n) != nil { | 
|  | n++ | 
|  | } | 
|  |  | 
|  | // skip NULL separator | 
|  | n++ | 
|  |  | 
|  | // now argv+n is auxv | 
|  | auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) | 
|  | sysauxv(auxv[:]) | 
|  | } | 
|  |  | 
|  | const ( | 
|  | _AT_NULL     = 0  // Terminates the vector | 
|  | _AT_PAGESZ   = 6  // Page size in bytes | 
|  | _AT_TIMEKEEP = 22 // Pointer to timehands. | 
|  | _AT_HWCAP    = 25 // CPU feature flags | 
|  | _AT_HWCAP2   = 26 // CPU feature flags 2 | 
|  | ) | 
|  |  | 
|  | func sysauxv(auxv []uintptr) { | 
|  | for i := 0; auxv[i] != _AT_NULL; i += 2 { | 
|  | tag, val := auxv[i], auxv[i+1] | 
|  | switch tag { | 
|  | // _AT_NCPUS from auxv shouldn't be used due to golang.org/issue/15206 | 
|  | case _AT_PAGESZ: | 
|  | physPageSize = val | 
|  | case _AT_TIMEKEEP: | 
|  | timekeepSharedPage = (*vdsoTimekeep)(unsafe.Pointer(val)) | 
|  | } | 
|  |  | 
|  | archauxv(tag, val) | 
|  | } | 
|  | } |