...

Source file src/github.com/tklauser/go-sysconf/sysconf_linux.go

Documentation: github.com/tklauser/go-sysconf

     1  // Copyright 2018 Tobias Klauser. 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 sysconf
     6  
     7  import (
     8  	"bufio"
     9  	"io/ioutil"
    10  	"os"
    11  	"runtime"
    12  	"strconv"
    13  	"strings"
    14  
    15  	"github.com/tklauser/numcpus"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  const (
    20  	// CLK_TCK is a constant on Linux for all architectures except alpha and ia64.
    21  	// See e.g.
    22  	// https://git.musl-libc.org/cgit/musl/tree/src/conf/sysconf.c#n30
    23  	// https://github.com/containerd/cgroups/pull/12
    24  	// https://lore.kernel.org/lkml/agtlq6$iht$1@penguin.transmeta.com/
    25  	_SYSTEM_CLK_TCK = 100
    26  )
    27  
    28  func readProcFsInt64(path string, fallback int64) int64 {
    29  	data, err := ioutil.ReadFile(path)
    30  	if err != nil {
    31  		return fallback
    32  	}
    33  	i, err := strconv.ParseInt(string(data[:len(data)-1]), 0, 64)
    34  	if err != nil {
    35  		return fallback
    36  	}
    37  	return i
    38  }
    39  
    40  // getMemPages computes mem*unit/os.Getpagesize(), but avoids overflowing int64.
    41  func getMemPages(mem uint64, unit uint32) int64 {
    42  	pageSize := os.Getpagesize()
    43  	for unit > 1 && pageSize > 1 {
    44  		unit >>= 1
    45  		pageSize >>= 1
    46  	}
    47  	mem *= uint64(unit)
    48  	for pageSize > 1 {
    49  		pageSize >>= 1
    50  		mem >>= 1
    51  	}
    52  	return int64(mem)
    53  }
    54  
    55  func getPhysPages() int64 {
    56  	var si unix.Sysinfo_t
    57  	err := unix.Sysinfo(&si)
    58  	if err != nil {
    59  		return int64(0)
    60  	}
    61  	return getMemPages(uint64(si.Totalram), si.Unit)
    62  }
    63  
    64  func getAvPhysPages() int64 {
    65  	var si unix.Sysinfo_t
    66  	err := unix.Sysinfo(&si)
    67  	if err != nil {
    68  		return int64(0)
    69  	}
    70  	return getMemPages(uint64(si.Freeram), si.Unit)
    71  }
    72  
    73  func getNprocsSysfs() (int64, error) {
    74  	n, err := numcpus.GetOnline()
    75  	return int64(n), err
    76  }
    77  
    78  func getNprocsProcStat() (int64, error) {
    79  	f, err := os.Open("/proc/stat")
    80  	if err != nil {
    81  		return -1, err
    82  	}
    83  	defer f.Close()
    84  
    85  	count := int64(0)
    86  	s := bufio.NewScanner(f)
    87  	for s.Scan() {
    88  		if line := strings.TrimSpace(s.Text()); strings.HasPrefix(line, "cpu") {
    89  			l := strings.SplitN(line, " ", 2)
    90  			_, err := strconv.ParseInt(l[0][3:], 10, 64)
    91  			if err == nil {
    92  				count++
    93  			}
    94  		} else {
    95  			// The current format of /proc/stat has all the
    96  			// cpu* lines at the beginning. Assume this
    97  			// stays this way.
    98  			break
    99  		}
   100  	}
   101  	return count, nil
   102  }
   103  
   104  func getNprocs() int64 {
   105  	count, err := getNprocsSysfs()
   106  	if err == nil {
   107  		return count
   108  	}
   109  
   110  	count, err = getNprocsProcStat()
   111  	if err == nil {
   112  		return count
   113  	}
   114  
   115  	// default to the value determined at runtime startup if all else fails
   116  	return int64(runtime.NumCPU())
   117  }
   118  
   119  func getNprocsConf() int64 {
   120  	count, err := numcpus.GetConfigured()
   121  	if err == nil {
   122  		return int64(count)
   123  	}
   124  
   125  	// TODO(tk): fall back to reading /proc/cpuinfo on legacy systems
   126  	// without sysfs?
   127  
   128  	return getNprocs()
   129  }
   130  
   131  func hasClock(clockid int32) bool {
   132  	var res unix.Timespec
   133  	if err := unix.ClockGetres(clockid, &res); err != nil {
   134  		return false
   135  	}
   136  	return true
   137  }
   138  
   139  func max(a, b int64) int64 {
   140  	if a > b {
   141  		return a
   142  	}
   143  	return b
   144  }
   145  
   146  func sysconf(name int) (int64, error) {
   147  	switch name {
   148  	case SC_AIO_LISTIO_MAX:
   149  		return -1, nil
   150  	case SC_AIO_MAX:
   151  		return -1, nil
   152  	case SC_AIO_PRIO_DELTA_MAX:
   153  		return _AIO_PRIO_DELTA_MAX, nil
   154  	case SC_ARG_MAX:
   155  		argMax := int64(_POSIX_ARG_MAX)
   156  		var rlim unix.Rlimit
   157  		if err := unix.Getrlimit(unix.RLIMIT_STACK, &rlim); err == nil {
   158  			argMax = max(argMax, int64(rlim.Cur/4))
   159  		}
   160  		return argMax, nil
   161  	case SC_ATEXIT_MAX:
   162  		return _INT_MAX, nil
   163  	case SC_CHILD_MAX:
   164  		childMax := int64(-1)
   165  		var rlim unix.Rlimit
   166  		if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlim); err == nil && rlim.Cur != unix.RLIM_INFINITY {
   167  			childMax = int64(rlim.Cur)
   168  		}
   169  		return childMax, nil
   170  	case SC_CLK_TCK:
   171  		return _SYSTEM_CLK_TCK, nil
   172  	case SC_DELAYTIMER_MAX:
   173  		return _DELAYTIMER_MAX, nil
   174  	case SC_GETGR_R_SIZE_MAX:
   175  		return _NSS_BUFLEN_GROUP, nil
   176  	case SC_GETPW_R_SIZE_MAX:
   177  		return _NSS_BUFLEN_PASSWD, nil
   178  	case SC_MQ_OPEN_MAX:
   179  		return -1, nil
   180  	case SC_MQ_PRIO_MAX:
   181  		return _MQ_PRIO_MAX, nil
   182  	case SC_NGROUPS_MAX:
   183  		return readProcFsInt64("/proc/sys/kernel/ngroups_max", _NGROUPS_MAX), nil
   184  	case SC_OPEN_MAX:
   185  		openMax := int64(_OPEN_MAX)
   186  		var rlim unix.Rlimit
   187  		if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlim); err == nil {
   188  			openMax = int64(rlim.Cur)
   189  		}
   190  		return openMax, nil
   191  	case SC_RTSIG_MAX:
   192  		return _RTSIG_MAX, nil
   193  	case SC_SEM_NSEMS_MAX:
   194  		return -1, nil
   195  	case SC_SEM_VALUE_MAX:
   196  		return _SEM_VALUE_MAX, nil
   197  	case SC_SIGQUEUE_MAX:
   198  		var rlim unix.Rlimit
   199  		if err := unix.Getrlimit(unix.RLIMIT_SIGPENDING, &rlim); err == nil {
   200  			return int64(rlim.Cur), nil
   201  		}
   202  		return readProcFsInt64("/proc/sys/kernel/rtsig-max", _POSIX_SIGQUEUE_MAX), nil
   203  	case SC_STREAM_MAX:
   204  		return _STREAM_MAX, nil
   205  	case SC_THREAD_DESTRUCTOR_ITERATIONS:
   206  		return _POSIX_THREAD_DESTRUCTOR_ITERATIONS, nil
   207  	case SC_THREAD_KEYS_MAX:
   208  		return _PTHREAD_KEYS_MAX, nil
   209  	case SC_THREAD_PRIO_INHERIT:
   210  		return _POSIX_THREAD_PRIO_INHERIT, nil
   211  	case SC_THREAD_PRIO_PROTECT:
   212  		return _POSIX_THREAD_PRIO_PROTECT, nil
   213  	case SC_THREAD_STACK_MIN:
   214  		return _PTHREAD_STACK_MIN, nil
   215  	case SC_THREAD_THREADS_MAX:
   216  		return -1, nil
   217  	case SC_TIMER_MAX:
   218  		return -1, nil
   219  	case SC_TTY_NAME_MAX:
   220  		return _TTY_NAME_MAX, nil
   221  	case SC_TZNAME_MAX:
   222  		return -1, nil
   223  
   224  	case SC_CPUTIME:
   225  		if hasClock(unix.CLOCK_PROCESS_CPUTIME_ID) {
   226  			return _POSIX_VERSION, nil
   227  		}
   228  		return -1, nil
   229  	case SC_MONOTONIC_CLOCK:
   230  		if hasClock(unix.CLOCK_MONOTONIC) {
   231  			return _POSIX_VERSION, nil
   232  		}
   233  		return -1, nil
   234  	case SC_SAVED_IDS:
   235  		return _POSIX_SAVED_IDS, nil
   236  	case SC_SPAWN:
   237  		return _POSIX_SPAWN, nil
   238  	case SC_SPIN_LOCKS:
   239  		return _POSIX_SPIN_LOCKS, nil
   240  	case SC_SPORADIC_SERVER:
   241  		return _POSIX_SPORADIC_SERVER, nil
   242  	case SC_SYNCHRONIZED_IO:
   243  		return _POSIX_SYNCHRONIZED_IO, nil
   244  	case SC_THREAD_ATTR_STACKADDR:
   245  		return _POSIX_THREAD_ATTR_STACKADDR, nil
   246  	case SC_THREAD_ATTR_STACKSIZE:
   247  		return _POSIX_THREAD_ATTR_STACKSIZE, nil
   248  	case SC_THREAD_CPUTIME:
   249  		if hasClock(unix.CLOCK_THREAD_CPUTIME_ID) {
   250  			return _POSIX_VERSION, nil
   251  		}
   252  		return -1, nil
   253  	case SC_THREAD_PRIORITY_SCHEDULING:
   254  		return _POSIX_THREAD_PRIORITY_SCHEDULING, nil
   255  	case SC_THREAD_PROCESS_SHARED:
   256  		return _POSIX_THREAD_PROCESS_SHARED, nil
   257  	case SC_THREAD_SAFE_FUNCTIONS:
   258  		return _POSIX_THREAD_SAFE_FUNCTIONS, nil
   259  	case SC_THREAD_SPORADIC_SERVER:
   260  		return _POSIX_THREAD_SPORADIC_SERVER, nil
   261  	case SC_TRACE:
   262  		return _POSIX_TRACE, nil
   263  	case SC_TRACE_EVENT_FILTER:
   264  		return _POSIX_TRACE_EVENT_FILTER, nil
   265  	case SC_TRACE_EVENT_NAME_MAX:
   266  		return -1, nil
   267  	case SC_TRACE_INHERIT:
   268  		return _POSIX_TRACE_INHERIT, nil
   269  	case SC_TRACE_LOG:
   270  		return _POSIX_TRACE_LOG, nil
   271  	case SC_TRACE_NAME_MAX:
   272  		return -1, nil
   273  	case SC_TRACE_SYS_MAX:
   274  		return -1, nil
   275  	case SC_TRACE_USER_EVENT_MAX:
   276  		return -1, nil
   277  	case SC_TYPED_MEMORY_OBJECTS:
   278  		return _POSIX_TYPED_MEMORY_OBJECTS, nil
   279  
   280  	case SC_V7_ILP32_OFF32:
   281  		return _POSIX_V7_ILP32_OFF32, nil
   282  	case SC_V7_ILP32_OFFBIG:
   283  		return _POSIX_V7_ILP32_OFFBIG, nil
   284  	case SC_V7_LP64_OFF64:
   285  		return _POSIX_V7_LP64_OFF64, nil
   286  	case SC_V7_LPBIG_OFFBIG:
   287  		return _POSIX_V7_LPBIG_OFFBIG, nil
   288  
   289  	case SC_V6_ILP32_OFF32:
   290  		return _POSIX_V6_ILP32_OFF32, nil
   291  	case SC_V6_ILP32_OFFBIG:
   292  		return _POSIX_V6_ILP32_OFFBIG, nil
   293  	case SC_V6_LP64_OFF64:
   294  		return _POSIX_V6_LP64_OFF64, nil
   295  	case SC_V6_LPBIG_OFFBIG:
   296  		return _POSIX_V6_LPBIG_OFFBIG, nil
   297  
   298  	case SC_2_C_VERSION:
   299  		return _POSIX2_C_VERSION, nil
   300  	case SC_2_CHAR_TERM:
   301  		return _POSIX2_CHAR_TERM, nil
   302  	case SC_2_PBS,
   303  		SC_2_PBS_ACCOUNTING,
   304  		SC_2_PBS_CHECKPOINT,
   305  		SC_2_PBS_LOCATE,
   306  		SC_2_PBS_MESSAGE,
   307  		SC_2_PBS_TRACK:
   308  		return -1, nil
   309  	case SC_2_UPE:
   310  		return -1, nil
   311  
   312  	case SC_XOPEN_CRYPT:
   313  		// removed in glibc 2.28
   314  		return -1, nil
   315  	case SC_XOPEN_ENH_I18N:
   316  		return _XOPEN_ENH_I18N, nil
   317  	case SC_XOPEN_REALTIME:
   318  		return _XOPEN_REALTIME, nil
   319  	case SC_XOPEN_REALTIME_THREADS:
   320  		return _XOPEN_REALTIME_THREADS, nil
   321  	case SC_XOPEN_SHM:
   322  		return _XOPEN_SHM, nil
   323  	case SC_XOPEN_STREAMS:
   324  		return -1, nil
   325  	case SC_XOPEN_UNIX:
   326  		return _XOPEN_UNIX, nil
   327  	case SC_XOPEN_VERSION:
   328  		return _XOPEN_VERSION, nil
   329  	case SC_XOPEN_XCU_VERSION:
   330  		return _XOPEN_XCU_VERSION, nil
   331  
   332  	case SC_PHYS_PAGES:
   333  		return getPhysPages(), nil
   334  	case SC_AVPHYS_PAGES:
   335  		return getAvPhysPages(), nil
   336  	case SC_NPROCESSORS_CONF:
   337  		return getNprocsConf(), nil
   338  	case SC_NPROCESSORS_ONLN:
   339  		return getNprocs(), nil
   340  	case SC_UIO_MAXIOV: // same as _SC_IOV_MAX
   341  		return _UIO_MAXIOV, nil
   342  	}
   343  
   344  	return sysconfGeneric(name)
   345  }
   346  

View as plain text