status-go/vendor/github.com/tklauser/go-sysconf/sysconf_linux.go

358 lines
8.3 KiB
Go

// Copyright 2018 Tobias Klauser. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sysconf
import (
"bufio"
"io/ioutil"
"os"
"runtime"
"strconv"
"strings"
"github.com/tklauser/numcpus"
"golang.org/x/sys/unix"
)
const (
// CLK_TCK is a constant on Linux, see e.g.
// https://git.musl-libc.org/cgit/musl/tree/src/conf/sysconf.c#n30 and
// https://github.com/containerd/cgroups/pull/12
_SYSTEM_CLK_TCK = 100
)
func readProcFsInt64(path string, fallback int64) int64 {
data, err := ioutil.ReadFile(path)
if err != nil {
return fallback
}
i, err := strconv.ParseInt(string(data[:len(data)-1]), 0, 64)
if err != nil {
return fallback
}
return i
}
// getMemPages computes mem*unit/os.Getpagesize(), but avoids overflowing int64.
func getMemPages(mem uint64, unit uint32) int64 {
pageSize := os.Getpagesize()
for unit > 1 && pageSize > 1 {
unit >>= 1
pageSize >>= 1
}
mem *= uint64(unit)
for pageSize > 1 {
pageSize >>= 1
mem >>= 1
}
return int64(mem)
}
func getPhysPages() int64 {
var si unix.Sysinfo_t
err := unix.Sysinfo(&si)
if err != nil {
return int64(0)
}
return getMemPages(uint64(si.Totalram), si.Unit)
}
func getAvPhysPages() int64 {
var si unix.Sysinfo_t
err := unix.Sysinfo(&si)
if err != nil {
return int64(0)
}
return getMemPages(uint64(si.Freeram), si.Unit)
}
func getNprocsSysfs() (int64, error) {
n, err := numcpus.GetOnline()
return int64(n), err
}
func getNprocsProcStat() (int64, error) {
f, err := os.Open("/proc/stat")
if err != nil {
return -1, err
}
defer f.Close()
count := int64(0)
s := bufio.NewScanner(f)
for s.Scan() {
if line := strings.TrimSpace(s.Text()); strings.HasPrefix(line, "cpu") {
l := strings.SplitN(line, " ", 2)
_, err := strconv.ParseInt(l[0][3:], 10, 64)
if err == nil {
count++
}
} else {
// The current format of /proc/stat has all the
// cpu* lines at the beginning. Assume this
// stays this way.
break
}
}
return count, nil
}
func getNprocs() int64 {
count, err := getNprocsSysfs()
if err == nil {
return count
}
count, err = getNprocsProcStat()
if err == nil {
return count
}
// default to the value determined at runtime startup if all else fails
return int64(runtime.NumCPU())
}
func getNprocsConf() int64 {
// TODO(tk): read /sys/devices/system/cpu/present instead?
d, err := os.Open("/sys/devices/system/cpu")
if err == nil {
defer d.Close()
fis, err := d.Readdir(-1)
if err == nil {
count := int64(0)
for _, fi := range fis {
if name := fi.Name(); fi.IsDir() && strings.HasPrefix(name, "cpu") {
_, err := strconv.ParseInt(name[3:], 10, 64)
if err == nil {
count++
}
}
}
return count
}
}
// TODO(tk): fall back to reading /proc/cpuinfo on legacy systems
// without sysfs?
return getNprocs()
}
func hasClock(clockid int32) bool {
var res unix.Timespec
if err := unix.ClockGetres(clockid, &res); err != nil {
return false
}
return true
}
func max(a, b int64) int64 {
if a > b {
return a
}
return b
}
func sysconf(name int) (int64, error) {
switch name {
case SC_AIO_LISTIO_MAX:
return -1, nil
case SC_AIO_MAX:
return -1, nil
case SC_AIO_PRIO_DELTA_MAX:
return _AIO_PRIO_DELTA_MAX, nil
case SC_ARG_MAX:
argMax := int64(_POSIX_ARG_MAX)
var rlim unix.Rlimit
if err := unix.Getrlimit(unix.RLIMIT_STACK, &rlim); err == nil {
argMax = max(argMax, int64(rlim.Cur/4))
}
return argMax, nil
case SC_ATEXIT_MAX:
return _INT_MAX, nil
case SC_CHILD_MAX:
childMax := int64(-1)
var rlim unix.Rlimit
if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlim); err == nil && rlim.Cur != unix.RLIM_INFINITY {
childMax = int64(rlim.Cur)
}
return childMax, nil
case SC_CLK_TCK:
return _SYSTEM_CLK_TCK, nil
case SC_DELAYTIMER_MAX:
return _DELAYTIMER_MAX, nil
case SC_GETGR_R_SIZE_MAX:
return _NSS_BUFLEN_GROUP, nil
case SC_GETPW_R_SIZE_MAX:
return _NSS_BUFLEN_PASSWD, nil
case SC_MQ_OPEN_MAX:
return -1, nil
case SC_MQ_PRIO_MAX:
return _MQ_PRIO_MAX, nil
case SC_NGROUPS_MAX:
return readProcFsInt64("/proc/sys/kernel/ngroups_max", _NGROUPS_MAX), nil
case SC_OPEN_MAX:
openMax := int64(_OPEN_MAX)
var rlim unix.Rlimit
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
openMax = int64(rlim.Cur)
}
return openMax, nil
case SC_RTSIG_MAX:
return _RTSIG_MAX, nil
case SC_SEM_NSEMS_MAX:
return -1, nil
case SC_SEM_VALUE_MAX:
return _SEM_VALUE_MAX, nil
case SC_SIGQUEUE_MAX:
var rlim unix.Rlimit
if err := unix.Getrlimit(unix.RLIMIT_SIGPENDING, &rlim); err == nil {
return int64(rlim.Cur), nil
}
return readProcFsInt64("/proc/sys/kernel/rtsig-max", _POSIX_SIGQUEUE_MAX), nil
case SC_STREAM_MAX:
return _STREAM_MAX, nil
case SC_THREAD_DESTRUCTOR_ITERATIONS:
return _POSIX_THREAD_DESTRUCTOR_ITERATIONS, nil
case SC_THREAD_KEYS_MAX:
return _PTHREAD_KEYS_MAX, nil
case SC_THREAD_PRIO_INHERIT:
return _POSIX_THREAD_PRIO_INHERIT, nil
case SC_THREAD_PRIO_PROTECT:
return _POSIX_THREAD_PRIO_PROTECT, nil
case SC_THREAD_STACK_MIN:
return _PTHREAD_STACK_MIN, nil
case SC_THREAD_THREADS_MAX:
return -1, nil
case SC_TIMER_MAX:
return -1, nil
case SC_TTY_NAME_MAX:
return _TTY_NAME_MAX, nil
case SC_TZNAME_MAX:
return -1, nil
case SC_CPUTIME:
if hasClock(unix.CLOCK_PROCESS_CPUTIME_ID) {
return _POSIX_VERSION, nil
}
return -1, nil
case SC_MONOTONIC_CLOCK:
if hasClock(unix.CLOCK_MONOTONIC) {
return _POSIX_VERSION, nil
}
return -1, nil
case SC_SAVED_IDS:
return _POSIX_SAVED_IDS, nil
case SC_SPAWN:
return _POSIX_SPAWN, nil
case SC_SPIN_LOCKS:
return _POSIX_SPIN_LOCKS, nil
case SC_SPORADIC_SERVER:
return _POSIX_SPORADIC_SERVER, nil
case SC_SYNCHRONIZED_IO:
return _POSIX_SYNCHRONIZED_IO, nil
case SC_THREAD_ATTR_STACKADDR:
return _POSIX_THREAD_ATTR_STACKADDR, nil
case SC_THREAD_ATTR_STACKSIZE:
return _POSIX_THREAD_ATTR_STACKSIZE, nil
case SC_THREAD_CPUTIME:
if hasClock(unix.CLOCK_THREAD_CPUTIME_ID) {
return _POSIX_VERSION, nil
}
return -1, nil
case SC_THREAD_PRIORITY_SCHEDULING:
return _POSIX_THREAD_PRIORITY_SCHEDULING, nil
case SC_THREAD_PROCESS_SHARED:
return _POSIX_THREAD_PROCESS_SHARED, nil
case SC_THREAD_SAFE_FUNCTIONS:
return _POSIX_THREAD_SAFE_FUNCTIONS, nil
case SC_THREAD_SPORADIC_SERVER:
return _POSIX_THREAD_SPORADIC_SERVER, nil
case SC_TRACE:
return _POSIX_TRACE, nil
case SC_TRACE_EVENT_FILTER:
return _POSIX_TRACE_EVENT_FILTER, nil
case SC_TRACE_EVENT_NAME_MAX:
return -1, nil
case SC_TRACE_INHERIT:
return _POSIX_TRACE_INHERIT, nil
case SC_TRACE_LOG:
return _POSIX_TRACE_LOG, nil
case SC_TRACE_NAME_MAX:
return -1, nil
case SC_TRACE_SYS_MAX:
return -1, nil
case SC_TRACE_USER_EVENT_MAX:
return -1, nil
case SC_TYPED_MEMORY_OBJECTS:
return _POSIX_TYPED_MEMORY_OBJECTS, nil
case SC_V7_ILP32_OFF32:
return _POSIX_V7_ILP32_OFF32, nil
case SC_V7_ILP32_OFFBIG:
return _POSIX_V7_ILP32_OFFBIG, nil
case SC_V7_LP64_OFF64:
return _POSIX_V7_LP64_OFF64, nil
case SC_V7_LPBIG_OFFBIG:
return _POSIX_V7_LPBIG_OFFBIG, nil
case SC_V6_ILP32_OFF32:
return _POSIX_V6_ILP32_OFF32, nil
case SC_V6_ILP32_OFFBIG:
return _POSIX_V6_ILP32_OFFBIG, nil
case SC_V6_LP64_OFF64:
return _POSIX_V6_LP64_OFF64, nil
case SC_V6_LPBIG_OFFBIG:
return _POSIX_V6_LPBIG_OFFBIG, nil
case SC_2_C_VERSION:
return _POSIX2_C_VERSION, nil
case SC_2_CHAR_TERM:
return _POSIX2_CHAR_TERM, nil
case SC_2_PBS,
SC_2_PBS_ACCOUNTING,
SC_2_PBS_CHECKPOINT,
SC_2_PBS_LOCATE,
SC_2_PBS_MESSAGE,
SC_2_PBS_TRACK:
return -1, nil
case SC_2_UPE:
return -1, nil
case SC_XOPEN_CRYPT:
// removed in glibc 2.28
return -1, nil
case SC_XOPEN_ENH_I18N:
return _XOPEN_ENH_I18N, nil
case SC_XOPEN_REALTIME:
return _XOPEN_REALTIME, nil
case SC_XOPEN_REALTIME_THREADS:
return _XOPEN_REALTIME_THREADS, nil
case SC_XOPEN_SHM:
return _XOPEN_SHM, nil
case SC_XOPEN_STREAMS:
return -1, nil
case SC_XOPEN_UNIX:
return _XOPEN_UNIX, nil
case SC_XOPEN_VERSION:
return _XOPEN_VERSION, nil
case SC_XOPEN_XCU_VERSION:
return _XOPEN_XCU_VERSION, nil
case SC_PHYS_PAGES:
return getPhysPages(), nil
case SC_AVPHYS_PAGES:
return getAvPhysPages(), nil
case SC_NPROCESSORS_CONF:
return getNprocsConf(), nil
case SC_NPROCESSORS_ONLN:
return getNprocs(), nil
case SC_UIO_MAXIOV: // same as _SC_IOV_MAX
return _UIO_MAXIOV, nil
}
return sysconfGeneric(name)
}