sysconf_linux.go 8.1 KB

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