os.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "os.h"
  3. // ----------------------------------------------------------------------------
  4. // system functions
  5. // to retrieve settings of the system
  6. #define CPUS_FOR_COLLECTORS 0
  7. #define CPUS_FOR_NETDATA 1
  8. long get_system_cpus_with_cache(bool cache, bool for_netdata) {
  9. static long processors[2] = { 0, 0 };
  10. int index = for_netdata ? CPUS_FOR_NETDATA : CPUS_FOR_COLLECTORS;
  11. if(likely(cache && processors[index] > 0))
  12. return processors[index];
  13. #if defined(__APPLE__) || defined(__FreeBSD__)
  14. #if defined(__APPLE__)
  15. #define HW_CPU_NAME "hw.logicalcpu"
  16. #else
  17. #define HW_CPU_NAME "hw.ncpu"
  18. #endif
  19. int32_t tmp_processors;
  20. bool error = false;
  21. if (unlikely(GETSYSCTL_BY_NAME(HW_CPU_NAME, tmp_processors)))
  22. error = true;
  23. else
  24. processors[index] = tmp_processors;
  25. if(processors[index] < 1) {
  26. processors[index] = 1;
  27. if(error)
  28. error("Assuming system has %d processors.", processors[index]);
  29. }
  30. return processors[index];
  31. #else
  32. char filename[FILENAME_MAX + 1];
  33. snprintfz(filename, FILENAME_MAX, "%s/proc/stat",
  34. (!for_netdata && netdata_configured_host_prefix) ? netdata_configured_host_prefix : "");
  35. procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
  36. if(!ff) {
  37. processors[index] = 1;
  38. error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
  39. return processors[index];
  40. }
  41. ff = procfile_readall(ff);
  42. if(!ff) {
  43. processors[index] = 1;
  44. error("Cannot open file '%s'. Assuming system has %ld processors.", filename, processors[index]);
  45. return processors[index];
  46. }
  47. long tmp_processors = 0;
  48. unsigned int i;
  49. for(i = 0; i < procfile_lines(ff); i++) {
  50. if(!procfile_linewords(ff, i)) continue;
  51. if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0)
  52. tmp_processors++;
  53. }
  54. procfile_close(ff);
  55. processors[index] = --tmp_processors;
  56. if(processors[index] < 1)
  57. processors[index] = 1;
  58. debug(D_SYSTEM, "System has %ld processors.", processors[index]);
  59. return processors[index];
  60. #endif /* __APPLE__, __FreeBSD__ */
  61. }
  62. pid_t pid_max = 32768;
  63. pid_t get_system_pid_max(void) {
  64. #ifdef __APPLE__
  65. // As we currently do not know a solution to query pid_max from the os
  66. // we use the number defined in bsd/sys/proc_internal.h in XNU sources
  67. pid_max = 99999;
  68. return pid_max;
  69. #elif __FreeBSD__
  70. int32_t tmp_pid_max;
  71. if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
  72. pid_max = 99999;
  73. error("Assuming system's maximum pid is %d.", pid_max);
  74. } else {
  75. pid_max = tmp_pid_max;
  76. }
  77. return pid_max;
  78. #else
  79. static char read = 0;
  80. if(unlikely(read)) return pid_max;
  81. read = 1;
  82. char filename[FILENAME_MAX + 1];
  83. snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix?netdata_configured_host_prefix:"");
  84. unsigned long long max = 0;
  85. if(read_single_number_file(filename, &max) != 0) {
  86. error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
  87. return pid_max;
  88. }
  89. if(!max) {
  90. error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
  91. return pid_max;
  92. }
  93. pid_max = (pid_t) max;
  94. return pid_max;
  95. #endif /* __APPLE__, __FreeBSD__ */
  96. }
  97. unsigned int system_hz;
  98. void get_system_HZ(void) {
  99. long ticks;
  100. if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
  101. error("Cannot get system clock ticks");
  102. }
  103. system_hz = (unsigned int) ticks;
  104. }
  105. static inline unsigned long cpuset_str2ul(char **s) {
  106. unsigned long n = 0;
  107. char c;
  108. for(c = **s; c >= '0' && c <= '9' ; c = *(++*s)) {
  109. n *= 10;
  110. n += c - '0';
  111. }
  112. return n;
  113. }
  114. unsigned long read_cpuset_cpus(const char *filename, long system_cpus) {
  115. static char *buf = NULL;
  116. static size_t buf_size = 0;
  117. if(!buf) {
  118. buf_size = 100U + 6 * system_cpus; // taken from kernel/cgroup/cpuset.c
  119. buf = mallocz(buf_size + 1);
  120. }
  121. int ret = read_file(filename, buf, buf_size);
  122. if(!ret) {
  123. char *s = buf;
  124. unsigned long ncpus = 0;
  125. // parse the cpuset string and calculate the number of cpus the cgroup is allowed to use
  126. while(*s) {
  127. unsigned long n = cpuset_str2ul(&s);
  128. ncpus++;
  129. if(*s == ',') {
  130. s++;
  131. continue;
  132. }
  133. if(*s == '-') {
  134. s++;
  135. unsigned long m = cpuset_str2ul(&s);
  136. ncpus += m - n; // calculate the number of cpus in the region
  137. }
  138. s++;
  139. }
  140. if(!ncpus)
  141. return 0;
  142. return ncpus;
  143. }
  144. return 0;
  145. }
  146. // =====================================================================================================================
  147. // FreeBSD
  148. #if __FreeBSD__
  149. const char *os_type = "freebsd";
  150. int getsysctl_by_name(const char *name, void *ptr, size_t len) {
  151. size_t nlen = len;
  152. if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
  153. error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
  154. return 1;
  155. }
  156. if (unlikely(nlen != len)) {
  157. error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
  158. return 1;
  159. }
  160. return 0;
  161. }
  162. int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len) {
  163. size_t nlen = len;
  164. if (unlikely(!mib[0]))
  165. if (unlikely(getsysctl_mib(name, mib, miblen)))
  166. return 1;
  167. if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
  168. error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
  169. return 1;
  170. }
  171. if (unlikely(nlen != len)) {
  172. error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
  173. return 1;
  174. }
  175. return 0;
  176. }
  177. int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len) {
  178. size_t nlen = *len;
  179. if (unlikely(!mib[0]))
  180. if (unlikely(getsysctl_mib(name, mib, miblen)))
  181. return 1;
  182. if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
  183. error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
  184. return 1;
  185. }
  186. if (unlikely(ptr != NULL && nlen != *len)) {
  187. error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
  188. return 1;
  189. }
  190. return 0;
  191. }
  192. int getsysctl_mib(const char *name, int *mib, size_t len) {
  193. size_t nlen = len;
  194. if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
  195. error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
  196. return 1;
  197. }
  198. if (unlikely(nlen != len)) {
  199. error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
  200. return 1;
  201. }
  202. return 0;
  203. }
  204. #endif
  205. // =====================================================================================================================
  206. // MacOS
  207. #if __APPLE__
  208. const char *os_type = "macos";
  209. int getsysctl_by_name(const char *name, void *ptr, size_t len) {
  210. size_t nlen = len;
  211. if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
  212. error("MACOS: sysctl(%s...) failed: %s", name, strerror(errno));
  213. return 1;
  214. }
  215. if (unlikely(nlen != len)) {
  216. error("MACOS: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
  217. return 1;
  218. }
  219. return 0;
  220. }
  221. #endif
  222. // =====================================================================================================================
  223. // Linux
  224. #if __linux__
  225. const char *os_type = "linux";
  226. #endif