xref: /netbsd-src/external/mit/libuv/dist/src/unix/linux-core.c (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
10e552da7Schristos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
20e552da7Schristos  * Permission is hereby granted, free of charge, to any person obtaining a copy
30e552da7Schristos  * of this software and associated documentation files (the "Software"), to
40e552da7Schristos  * deal in the Software without restriction, including without limitation the
50e552da7Schristos  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
60e552da7Schristos  * sell copies of the Software, and to permit persons to whom the Software is
70e552da7Schristos  * furnished to do so, subject to the following conditions:
80e552da7Schristos  *
90e552da7Schristos  * The above copyright notice and this permission notice shall be included in
100e552da7Schristos  * all copies or substantial portions of the Software.
110e552da7Schristos  *
120e552da7Schristos  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
130e552da7Schristos  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
140e552da7Schristos  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
150e552da7Schristos  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
160e552da7Schristos  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
170e552da7Schristos  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
180e552da7Schristos  * IN THE SOFTWARE.
190e552da7Schristos  */
200e552da7Schristos 
210e552da7Schristos /* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
220e552da7Schristos  * EPOLL* counterparts.  We use the POLL* variants in this file because that
230e552da7Schristos  * is what libuv uses elsewhere.
240e552da7Schristos  */
250e552da7Schristos 
260e552da7Schristos #include "uv.h"
270e552da7Schristos #include "internal.h"
280e552da7Schristos 
290e552da7Schristos #include <inttypes.h>
300e552da7Schristos #include <stdint.h>
310e552da7Schristos #include <stdio.h>
320e552da7Schristos #include <stdlib.h>
330e552da7Schristos #include <string.h>
340e552da7Schristos #include <assert.h>
350e552da7Schristos #include <errno.h>
360e552da7Schristos 
370e552da7Schristos #include <net/if.h>
380e552da7Schristos #include <sys/epoll.h>
390e552da7Schristos #include <sys/param.h>
400e552da7Schristos #include <sys/prctl.h>
410e552da7Schristos #include <sys/sysinfo.h>
420e552da7Schristos #include <unistd.h>
430e552da7Schristos #include <fcntl.h>
440e552da7Schristos #include <time.h>
450e552da7Schristos 
460e552da7Schristos #define HAVE_IFADDRS_H 1
470e552da7Schristos 
48*5f2f4271Schristos # if defined(__ANDROID_API__) && __ANDROID_API__ < 24
49*5f2f4271Schristos # undef HAVE_IFADDRS_H
50*5f2f4271Schristos #endif
51*5f2f4271Schristos 
520e552da7Schristos #ifdef __UCLIBC__
530e552da7Schristos # if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
540e552da7Schristos #  undef HAVE_IFADDRS_H
550e552da7Schristos # endif
560e552da7Schristos #endif
570e552da7Schristos 
580e552da7Schristos #ifdef HAVE_IFADDRS_H
590e552da7Schristos # include <ifaddrs.h>
600e552da7Schristos # include <sys/socket.h>
610e552da7Schristos # include <net/ethernet.h>
620e552da7Schristos # include <netpacket/packet.h>
630e552da7Schristos #endif /* HAVE_IFADDRS_H */
640e552da7Schristos 
650e552da7Schristos /* Available from 2.6.32 onwards. */
660e552da7Schristos #ifndef CLOCK_MONOTONIC_COARSE
670e552da7Schristos # define CLOCK_MONOTONIC_COARSE 6
680e552da7Schristos #endif
690e552da7Schristos 
700e552da7Schristos /* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
710e552da7Schristos  * include that file because it conflicts with <time.h>. We'll just have to
720e552da7Schristos  * define it ourselves.
730e552da7Schristos  */
740e552da7Schristos #ifndef CLOCK_BOOTTIME
750e552da7Schristos # define CLOCK_BOOTTIME 7
760e552da7Schristos #endif
770e552da7Schristos 
780e552da7Schristos static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
790e552da7Schristos static int read_times(FILE* statfile_fp,
800e552da7Schristos                       unsigned int numcpus,
810e552da7Schristos                       uv_cpu_info_t* ci);
820e552da7Schristos static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
830e552da7Schristos static uint64_t read_cpufreq(unsigned int cpunum);
840e552da7Schristos 
uv__platform_loop_init(uv_loop_t * loop)850e552da7Schristos int uv__platform_loop_init(uv_loop_t* loop) {
860e552da7Schristos 
870e552da7Schristos   loop->inotify_fd = -1;
880e552da7Schristos   loop->inotify_watchers = NULL;
890e552da7Schristos 
90*5f2f4271Schristos   return uv__epoll_init(loop);
910e552da7Schristos }
920e552da7Schristos 
930e552da7Schristos 
uv__io_fork(uv_loop_t * loop)940e552da7Schristos int uv__io_fork(uv_loop_t* loop) {
950e552da7Schristos   int err;
960e552da7Schristos   void* old_watchers;
970e552da7Schristos 
980e552da7Schristos   old_watchers = loop->inotify_watchers;
990e552da7Schristos 
1000e552da7Schristos   uv__close(loop->backend_fd);
1010e552da7Schristos   loop->backend_fd = -1;
1020e552da7Schristos   uv__platform_loop_delete(loop);
1030e552da7Schristos 
1040e552da7Schristos   err = uv__platform_loop_init(loop);
1050e552da7Schristos   if (err)
1060e552da7Schristos     return err;
1070e552da7Schristos 
1080e552da7Schristos   return uv__inotify_fork(loop, old_watchers);
1090e552da7Schristos }
1100e552da7Schristos 
1110e552da7Schristos 
uv__platform_loop_delete(uv_loop_t * loop)1120e552da7Schristos void uv__platform_loop_delete(uv_loop_t* loop) {
1130e552da7Schristos   if (loop->inotify_fd == -1) return;
1140e552da7Schristos   uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
1150e552da7Schristos   uv__close(loop->inotify_fd);
1160e552da7Schristos   loop->inotify_fd = -1;
1170e552da7Schristos }
1180e552da7Schristos 
1190e552da7Schristos 
1200e552da7Schristos 
uv__hrtime(uv_clocktype_t type)1210e552da7Schristos uint64_t uv__hrtime(uv_clocktype_t type) {
1220e552da7Schristos   static clock_t fast_clock_id = -1;
1230e552da7Schristos   struct timespec t;
1240e552da7Schristos   clock_t clock_id;
1250e552da7Schristos 
1260e552da7Schristos   /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
1270e552da7Schristos    * millisecond granularity or better.  CLOCK_MONOTONIC_COARSE is
1280e552da7Schristos    * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
1290e552da7Schristos    * decide to make a costly system call.
1300e552da7Schristos    */
1310e552da7Schristos   /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
1320e552da7Schristos    * when it has microsecond granularity or better (unlikely).
1330e552da7Schristos    */
134*5f2f4271Schristos   clock_id = CLOCK_MONOTONIC;
135*5f2f4271Schristos   if (type != UV_CLOCK_FAST)
136*5f2f4271Schristos     goto done;
137*5f2f4271Schristos 
138*5f2f4271Schristos   clock_id = uv__load_relaxed(&fast_clock_id);
139*5f2f4271Schristos   if (clock_id != -1)
140*5f2f4271Schristos     goto done;
1410e552da7Schristos 
1420e552da7Schristos   clock_id = CLOCK_MONOTONIC;
143*5f2f4271Schristos   if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t))
144*5f2f4271Schristos     if (t.tv_nsec <= 1 * 1000 * 1000)
145*5f2f4271Schristos       clock_id = CLOCK_MONOTONIC_COARSE;
146*5f2f4271Schristos 
147*5f2f4271Schristos   uv__store_relaxed(&fast_clock_id, clock_id);
148*5f2f4271Schristos 
149*5f2f4271Schristos done:
1500e552da7Schristos 
1510e552da7Schristos   if (clock_gettime(clock_id, &t))
1520e552da7Schristos     return 0;  /* Not really possible. */
1530e552da7Schristos 
1540e552da7Schristos   return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
1550e552da7Schristos }
1560e552da7Schristos 
1570e552da7Schristos 
uv_resident_set_memory(size_t * rss)1580e552da7Schristos int uv_resident_set_memory(size_t* rss) {
1590e552da7Schristos   char buf[1024];
1600e552da7Schristos   const char* s;
1610e552da7Schristos   ssize_t n;
1620e552da7Schristos   long val;
1630e552da7Schristos   int fd;
1640e552da7Schristos   int i;
1650e552da7Schristos 
1660e552da7Schristos   do
1670e552da7Schristos     fd = open("/proc/self/stat", O_RDONLY);
1680e552da7Schristos   while (fd == -1 && errno == EINTR);
1690e552da7Schristos 
1700e552da7Schristos   if (fd == -1)
1710e552da7Schristos     return UV__ERR(errno);
1720e552da7Schristos 
1730e552da7Schristos   do
1740e552da7Schristos     n = read(fd, buf, sizeof(buf) - 1);
1750e552da7Schristos   while (n == -1 && errno == EINTR);
1760e552da7Schristos 
1770e552da7Schristos   uv__close(fd);
1780e552da7Schristos   if (n == -1)
1790e552da7Schristos     return UV__ERR(errno);
1800e552da7Schristos   buf[n] = '\0';
1810e552da7Schristos 
1820e552da7Schristos   s = strchr(buf, ' ');
1830e552da7Schristos   if (s == NULL)
1840e552da7Schristos     goto err;
1850e552da7Schristos 
1860e552da7Schristos   s += 1;
1870e552da7Schristos   if (*s != '(')
1880e552da7Schristos     goto err;
1890e552da7Schristos 
1900e552da7Schristos   s = strchr(s, ')');
1910e552da7Schristos   if (s == NULL)
1920e552da7Schristos     goto err;
1930e552da7Schristos 
1940e552da7Schristos   for (i = 1; i <= 22; i++) {
1950e552da7Schristos     s = strchr(s + 1, ' ');
1960e552da7Schristos     if (s == NULL)
1970e552da7Schristos       goto err;
1980e552da7Schristos   }
1990e552da7Schristos 
2000e552da7Schristos   errno = 0;
2010e552da7Schristos   val = strtol(s, NULL, 10);
2020e552da7Schristos   if (errno != 0)
2030e552da7Schristos     goto err;
2040e552da7Schristos   if (val < 0)
2050e552da7Schristos     goto err;
2060e552da7Schristos 
2070e552da7Schristos   *rss = val * getpagesize();
2080e552da7Schristos   return 0;
2090e552da7Schristos 
2100e552da7Schristos err:
2110e552da7Schristos   return UV_EINVAL;
2120e552da7Schristos }
2130e552da7Schristos 
uv_uptime(double * uptime)2140e552da7Schristos int uv_uptime(double* uptime) {
2150e552da7Schristos   static volatile int no_clock_boottime;
216*5f2f4271Schristos   char buf[128];
2170e552da7Schristos   struct timespec now;
2180e552da7Schristos   int r;
2190e552da7Schristos 
220*5f2f4271Schristos   /* Try /proc/uptime first, then fallback to clock_gettime(). */
221*5f2f4271Schristos 
222*5f2f4271Schristos   if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
223*5f2f4271Schristos     if (1 == sscanf(buf, "%lf", uptime))
224*5f2f4271Schristos       return 0;
225*5f2f4271Schristos 
2260e552da7Schristos   /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
2270e552da7Schristos    * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
2280e552da7Schristos    * is suspended.
2290e552da7Schristos    */
2300e552da7Schristos   if (no_clock_boottime) {
231*5f2f4271Schristos     retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);
2320e552da7Schristos   }
2330e552da7Schristos   else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
2340e552da7Schristos     no_clock_boottime = 1;
235*5f2f4271Schristos     goto retry_clock_gettime;
2360e552da7Schristos   }
2370e552da7Schristos 
2380e552da7Schristos   if (r)
2390e552da7Schristos     return UV__ERR(errno);
2400e552da7Schristos 
2410e552da7Schristos   *uptime = now.tv_sec;
2420e552da7Schristos   return 0;
2430e552da7Schristos }
2440e552da7Schristos 
2450e552da7Schristos 
uv__cpu_num(FILE * statfile_fp,unsigned int * numcpus)2460e552da7Schristos static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
2470e552da7Schristos   unsigned int num;
2480e552da7Schristos   char buf[1024];
2490e552da7Schristos 
2500e552da7Schristos   if (!fgets(buf, sizeof(buf), statfile_fp))
2510e552da7Schristos     return UV_EIO;
2520e552da7Schristos 
2530e552da7Schristos   num = 0;
2540e552da7Schristos   while (fgets(buf, sizeof(buf), statfile_fp)) {
2550e552da7Schristos     if (strncmp(buf, "cpu", 3))
2560e552da7Schristos       break;
2570e552da7Schristos     num++;
2580e552da7Schristos   }
2590e552da7Schristos 
2600e552da7Schristos   if (num == 0)
2610e552da7Schristos     return UV_EIO;
2620e552da7Schristos 
2630e552da7Schristos   *numcpus = num;
2640e552da7Schristos   return 0;
2650e552da7Schristos }
2660e552da7Schristos 
2670e552da7Schristos 
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)2680e552da7Schristos int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
2690e552da7Schristos   unsigned int numcpus;
2700e552da7Schristos   uv_cpu_info_t* ci;
2710e552da7Schristos   int err;
2720e552da7Schristos   FILE* statfile_fp;
2730e552da7Schristos 
2740e552da7Schristos   *cpu_infos = NULL;
2750e552da7Schristos   *count = 0;
2760e552da7Schristos 
2770e552da7Schristos   statfile_fp = uv__open_file("/proc/stat");
2780e552da7Schristos   if (statfile_fp == NULL)
2790e552da7Schristos     return UV__ERR(errno);
2800e552da7Schristos 
2810e552da7Schristos   err = uv__cpu_num(statfile_fp, &numcpus);
2820e552da7Schristos   if (err < 0)
2830e552da7Schristos     goto out;
2840e552da7Schristos 
2850e552da7Schristos   err = UV_ENOMEM;
2860e552da7Schristos   ci = uv__calloc(numcpus, sizeof(*ci));
2870e552da7Schristos   if (ci == NULL)
2880e552da7Schristos     goto out;
2890e552da7Schristos 
2900e552da7Schristos   err = read_models(numcpus, ci);
2910e552da7Schristos   if (err == 0)
2920e552da7Schristos     err = read_times(statfile_fp, numcpus, ci);
2930e552da7Schristos 
2940e552da7Schristos   if (err) {
2950e552da7Schristos     uv_free_cpu_info(ci, numcpus);
2960e552da7Schristos     goto out;
2970e552da7Schristos   }
2980e552da7Schristos 
2990e552da7Schristos   /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
3000e552da7Schristos    * We don't check for errors here. Worst case, the field is left zero.
3010e552da7Schristos    */
3020e552da7Schristos   if (ci[0].speed == 0)
3030e552da7Schristos     read_speeds(numcpus, ci);
3040e552da7Schristos 
3050e552da7Schristos   *cpu_infos = ci;
3060e552da7Schristos   *count = numcpus;
3070e552da7Schristos   err = 0;
3080e552da7Schristos 
3090e552da7Schristos out:
3100e552da7Schristos 
3110e552da7Schristos   if (fclose(statfile_fp))
3120e552da7Schristos     if (errno != EINTR && errno != EINPROGRESS)
3130e552da7Schristos       abort();
3140e552da7Schristos 
3150e552da7Schristos   return err;
3160e552da7Schristos }
3170e552da7Schristos 
3180e552da7Schristos 
read_speeds(unsigned int numcpus,uv_cpu_info_t * ci)3190e552da7Schristos static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
3200e552da7Schristos   unsigned int num;
3210e552da7Schristos 
3220e552da7Schristos   for (num = 0; num < numcpus; num++)
3230e552da7Schristos     ci[num].speed = read_cpufreq(num) / 1000;
3240e552da7Schristos }
3250e552da7Schristos 
3260e552da7Schristos 
327*5f2f4271Schristos /* Also reads the CPU frequency on ppc and x86. The other architectures only
328*5f2f4271Schristos  * have a BogoMIPS field, which may not be very accurate.
3290e552da7Schristos  *
3300e552da7Schristos  * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
3310e552da7Schristos  */
read_models(unsigned int numcpus,uv_cpu_info_t * ci)3320e552da7Schristos static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
333*5f2f4271Schristos #if defined(__PPC__)
334*5f2f4271Schristos   static const char model_marker[] = "cpu\t\t: ";
335*5f2f4271Schristos   static const char speed_marker[] = "clock\t\t: ";
336*5f2f4271Schristos #else
3370e552da7Schristos   static const char model_marker[] = "model name\t: ";
3380e552da7Schristos   static const char speed_marker[] = "cpu MHz\t\t: ";
339*5f2f4271Schristos #endif
3400e552da7Schristos   const char* inferred_model;
3410e552da7Schristos   unsigned int model_idx;
3420e552da7Schristos   unsigned int speed_idx;
343*5f2f4271Schristos   unsigned int part_idx;
3440e552da7Schristos   char buf[1024];
3450e552da7Schristos   char* model;
3460e552da7Schristos   FILE* fp;
347*5f2f4271Schristos   int model_id;
3480e552da7Schristos 
3490e552da7Schristos   /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
3500e552da7Schristos   (void) &model_marker;
3510e552da7Schristos   (void) &speed_marker;
3520e552da7Schristos   (void) &speed_idx;
353*5f2f4271Schristos   (void) &part_idx;
3540e552da7Schristos   (void) &model;
3550e552da7Schristos   (void) &buf;
3560e552da7Schristos   (void) &fp;
357*5f2f4271Schristos   (void) &model_id;
3580e552da7Schristos 
3590e552da7Schristos   model_idx = 0;
3600e552da7Schristos   speed_idx = 0;
361*5f2f4271Schristos   part_idx = 0;
3620e552da7Schristos 
3630e552da7Schristos #if defined(__arm__) || \
3640e552da7Schristos     defined(__i386__) || \
3650e552da7Schristos     defined(__mips__) || \
366*5f2f4271Schristos     defined(__aarch64__) || \
367*5f2f4271Schristos     defined(__PPC__) || \
3680e552da7Schristos     defined(__x86_64__)
3690e552da7Schristos   fp = uv__open_file("/proc/cpuinfo");
3700e552da7Schristos   if (fp == NULL)
3710e552da7Schristos     return UV__ERR(errno);
3720e552da7Schristos 
3730e552da7Schristos   while (fgets(buf, sizeof(buf), fp)) {
3740e552da7Schristos     if (model_idx < numcpus) {
3750e552da7Schristos       if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
3760e552da7Schristos         model = buf + sizeof(model_marker) - 1;
3770e552da7Schristos         model = uv__strndup(model, strlen(model) - 1);  /* Strip newline. */
3780e552da7Schristos         if (model == NULL) {
3790e552da7Schristos           fclose(fp);
3800e552da7Schristos           return UV_ENOMEM;
3810e552da7Schristos         }
3820e552da7Schristos         ci[model_idx++].model = model;
3830e552da7Schristos         continue;
3840e552da7Schristos       }
3850e552da7Schristos     }
386*5f2f4271Schristos #if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
3870e552da7Schristos     if (model_idx < numcpus) {
3880e552da7Schristos #if defined(__arm__)
3890e552da7Schristos       /* Fallback for pre-3.8 kernels. */
3900e552da7Schristos       static const char model_marker[] = "Processor\t: ";
391*5f2f4271Schristos #elif defined(__aarch64__)
392*5f2f4271Schristos       static const char part_marker[] = "CPU part\t: ";
393*5f2f4271Schristos 
394*5f2f4271Schristos       /* Adapted from: https://github.com/karelzak/util-linux */
395*5f2f4271Schristos       struct vendor_part {
396*5f2f4271Schristos         const int id;
397*5f2f4271Schristos         const char* name;
398*5f2f4271Schristos       };
399*5f2f4271Schristos 
400*5f2f4271Schristos       static const struct vendor_part arm_chips[] = {
401*5f2f4271Schristos         { 0x811, "ARM810" },
402*5f2f4271Schristos         { 0x920, "ARM920" },
403*5f2f4271Schristos         { 0x922, "ARM922" },
404*5f2f4271Schristos         { 0x926, "ARM926" },
405*5f2f4271Schristos         { 0x940, "ARM940" },
406*5f2f4271Schristos         { 0x946, "ARM946" },
407*5f2f4271Schristos         { 0x966, "ARM966" },
408*5f2f4271Schristos         { 0xa20, "ARM1020" },
409*5f2f4271Schristos         { 0xa22, "ARM1022" },
410*5f2f4271Schristos         { 0xa26, "ARM1026" },
411*5f2f4271Schristos         { 0xb02, "ARM11 MPCore" },
412*5f2f4271Schristos         { 0xb36, "ARM1136" },
413*5f2f4271Schristos         { 0xb56, "ARM1156" },
414*5f2f4271Schristos         { 0xb76, "ARM1176" },
415*5f2f4271Schristos         { 0xc05, "Cortex-A5" },
416*5f2f4271Schristos         { 0xc07, "Cortex-A7" },
417*5f2f4271Schristos         { 0xc08, "Cortex-A8" },
418*5f2f4271Schristos         { 0xc09, "Cortex-A9" },
419*5f2f4271Schristos         { 0xc0d, "Cortex-A17" },  /* Originally A12 */
420*5f2f4271Schristos         { 0xc0f, "Cortex-A15" },
421*5f2f4271Schristos         { 0xc0e, "Cortex-A17" },
422*5f2f4271Schristos         { 0xc14, "Cortex-R4" },
423*5f2f4271Schristos         { 0xc15, "Cortex-R5" },
424*5f2f4271Schristos         { 0xc17, "Cortex-R7" },
425*5f2f4271Schristos         { 0xc18, "Cortex-R8" },
426*5f2f4271Schristos         { 0xc20, "Cortex-M0" },
427*5f2f4271Schristos         { 0xc21, "Cortex-M1" },
428*5f2f4271Schristos         { 0xc23, "Cortex-M3" },
429*5f2f4271Schristos         { 0xc24, "Cortex-M4" },
430*5f2f4271Schristos         { 0xc27, "Cortex-M7" },
431*5f2f4271Schristos         { 0xc60, "Cortex-M0+" },
432*5f2f4271Schristos         { 0xd01, "Cortex-A32" },
433*5f2f4271Schristos         { 0xd03, "Cortex-A53" },
434*5f2f4271Schristos         { 0xd04, "Cortex-A35" },
435*5f2f4271Schristos         { 0xd05, "Cortex-A55" },
436*5f2f4271Schristos         { 0xd06, "Cortex-A65" },
437*5f2f4271Schristos         { 0xd07, "Cortex-A57" },
438*5f2f4271Schristos         { 0xd08, "Cortex-A72" },
439*5f2f4271Schristos         { 0xd09, "Cortex-A73" },
440*5f2f4271Schristos         { 0xd0a, "Cortex-A75" },
441*5f2f4271Schristos         { 0xd0b, "Cortex-A76" },
442*5f2f4271Schristos         { 0xd0c, "Neoverse-N1" },
443*5f2f4271Schristos         { 0xd0d, "Cortex-A77" },
444*5f2f4271Schristos         { 0xd0e, "Cortex-A76AE" },
445*5f2f4271Schristos         { 0xd13, "Cortex-R52" },
446*5f2f4271Schristos         { 0xd20, "Cortex-M23" },
447*5f2f4271Schristos         { 0xd21, "Cortex-M33" },
448*5f2f4271Schristos         { 0xd41, "Cortex-A78" },
449*5f2f4271Schristos         { 0xd42, "Cortex-A78AE" },
450*5f2f4271Schristos         { 0xd4a, "Neoverse-E1" },
451*5f2f4271Schristos         { 0xd4b, "Cortex-A78C" },
452*5f2f4271Schristos       };
453*5f2f4271Schristos 
454*5f2f4271Schristos       if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {
455*5f2f4271Schristos         model = buf + sizeof(part_marker) - 1;
456*5f2f4271Schristos 
457*5f2f4271Schristos         errno = 0;
458*5f2f4271Schristos         model_id = strtol(model, NULL, 16);
459*5f2f4271Schristos         if ((errno != 0) || model_id < 0) {
460*5f2f4271Schristos           fclose(fp);
461*5f2f4271Schristos           return UV_EINVAL;
462*5f2f4271Schristos         }
463*5f2f4271Schristos 
464*5f2f4271Schristos         for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {
465*5f2f4271Schristos           if (model_id == arm_chips[part_idx].id) {
466*5f2f4271Schristos             model = uv__strdup(arm_chips[part_idx].name);
467*5f2f4271Schristos             if (model == NULL) {
468*5f2f4271Schristos               fclose(fp);
469*5f2f4271Schristos               return UV_ENOMEM;
470*5f2f4271Schristos             }
471*5f2f4271Schristos             ci[model_idx++].model = model;
472*5f2f4271Schristos             break;
473*5f2f4271Schristos           }
474*5f2f4271Schristos         }
475*5f2f4271Schristos       }
4760e552da7Schristos #else	/* defined(__mips__) */
4770e552da7Schristos       static const char model_marker[] = "cpu model\t\t: ";
4780e552da7Schristos #endif
4790e552da7Schristos       if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
4800e552da7Schristos         model = buf + sizeof(model_marker) - 1;
4810e552da7Schristos         model = uv__strndup(model, strlen(model) - 1);  /* Strip newline. */
4820e552da7Schristos         if (model == NULL) {
4830e552da7Schristos           fclose(fp);
4840e552da7Schristos           return UV_ENOMEM;
4850e552da7Schristos         }
4860e552da7Schristos         ci[model_idx++].model = model;
4870e552da7Schristos         continue;
4880e552da7Schristos       }
4890e552da7Schristos     }
490*5f2f4271Schristos #else  /* !__arm__ && !__mips__ && !__aarch64__ */
4910e552da7Schristos     if (speed_idx < numcpus) {
4920e552da7Schristos       if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
4930e552da7Schristos         ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
4940e552da7Schristos         continue;
4950e552da7Schristos       }
4960e552da7Schristos     }
497*5f2f4271Schristos #endif  /* __arm__ || __mips__ || __aarch64__ */
4980e552da7Schristos   }
4990e552da7Schristos 
5000e552da7Schristos   fclose(fp);
501*5f2f4271Schristos #endif  /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */
5020e552da7Schristos 
5030e552da7Schristos   /* Now we want to make sure that all the models contain *something* because
5040e552da7Schristos    * it's not safe to leave them as null. Copy the last entry unless there
5050e552da7Schristos    * isn't one, in that case we simply put "unknown" into everything.
5060e552da7Schristos    */
5070e552da7Schristos   inferred_model = "unknown";
5080e552da7Schristos   if (model_idx > 0)
5090e552da7Schristos     inferred_model = ci[model_idx - 1].model;
5100e552da7Schristos 
5110e552da7Schristos   while (model_idx < numcpus) {
5120e552da7Schristos     model = uv__strndup(inferred_model, strlen(inferred_model));
5130e552da7Schristos     if (model == NULL)
5140e552da7Schristos       return UV_ENOMEM;
5150e552da7Schristos     ci[model_idx++].model = model;
5160e552da7Schristos   }
5170e552da7Schristos 
5180e552da7Schristos   return 0;
5190e552da7Schristos }
5200e552da7Schristos 
5210e552da7Schristos 
read_times(FILE * statfile_fp,unsigned int numcpus,uv_cpu_info_t * ci)5220e552da7Schristos static int read_times(FILE* statfile_fp,
5230e552da7Schristos                       unsigned int numcpus,
5240e552da7Schristos                       uv_cpu_info_t* ci) {
5250e552da7Schristos   struct uv_cpu_times_s ts;
5260e552da7Schristos   unsigned int ticks;
5270e552da7Schristos   unsigned int multiplier;
5280e552da7Schristos   uint64_t user;
5290e552da7Schristos   uint64_t nice;
5300e552da7Schristos   uint64_t sys;
5310e552da7Schristos   uint64_t idle;
5320e552da7Schristos   uint64_t dummy;
5330e552da7Schristos   uint64_t irq;
5340e552da7Schristos   uint64_t num;
5350e552da7Schristos   uint64_t len;
5360e552da7Schristos   char buf[1024];
5370e552da7Schristos 
5380e552da7Schristos   ticks = (unsigned int)sysconf(_SC_CLK_TCK);
5390e552da7Schristos   assert(ticks != (unsigned int) -1);
5400e552da7Schristos   assert(ticks != 0);
541*5f2f4271Schristos   multiplier = ((uint64_t)1000L / ticks);
5420e552da7Schristos 
5430e552da7Schristos   rewind(statfile_fp);
5440e552da7Schristos 
5450e552da7Schristos   if (!fgets(buf, sizeof(buf), statfile_fp))
5460e552da7Schristos     abort();
5470e552da7Schristos 
5480e552da7Schristos   num = 0;
5490e552da7Schristos 
5500e552da7Schristos   while (fgets(buf, sizeof(buf), statfile_fp)) {
5510e552da7Schristos     if (num >= numcpus)
5520e552da7Schristos       break;
5530e552da7Schristos 
5540e552da7Schristos     if (strncmp(buf, "cpu", 3))
5550e552da7Schristos       break;
5560e552da7Schristos 
5570e552da7Schristos     /* skip "cpu<num> " marker */
5580e552da7Schristos     {
5590e552da7Schristos       unsigned int n;
5600e552da7Schristos       int r = sscanf(buf, "cpu%u ", &n);
5610e552da7Schristos       assert(r == 1);
5620e552da7Schristos       (void) r;  /* silence build warning */
5630e552da7Schristos       for (len = sizeof("cpu0"); n /= 10; len++);
5640e552da7Schristos     }
5650e552da7Schristos 
5660e552da7Schristos     /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
5670e552da7Schristos      * guest, guest_nice but we're only interested in the first four + irq.
5680e552da7Schristos      *
5690e552da7Schristos      * Don't use %*s to skip fields or %ll to read straight into the uint64_t
5700e552da7Schristos      * fields, they're not allowed in C89 mode.
5710e552da7Schristos      */
5720e552da7Schristos     if (6 != sscanf(buf + len,
5730e552da7Schristos                     "%" PRIu64 " %" PRIu64 " %" PRIu64
5740e552da7Schristos                     "%" PRIu64 " %" PRIu64 " %" PRIu64,
5750e552da7Schristos                     &user,
5760e552da7Schristos                     &nice,
5770e552da7Schristos                     &sys,
5780e552da7Schristos                     &idle,
5790e552da7Schristos                     &dummy,
5800e552da7Schristos                     &irq))
5810e552da7Schristos       abort();
5820e552da7Schristos 
5830e552da7Schristos     ts.user = user * multiplier;
5840e552da7Schristos     ts.nice = nice * multiplier;
5850e552da7Schristos     ts.sys  = sys * multiplier;
5860e552da7Schristos     ts.idle = idle * multiplier;
5870e552da7Schristos     ts.irq  = irq * multiplier;
5880e552da7Schristos     ci[num++].cpu_times = ts;
5890e552da7Schristos   }
5900e552da7Schristos   assert(num == numcpus);
5910e552da7Schristos 
5920e552da7Schristos   return 0;
5930e552da7Schristos }
5940e552da7Schristos 
5950e552da7Schristos 
read_cpufreq(unsigned int cpunum)5960e552da7Schristos static uint64_t read_cpufreq(unsigned int cpunum) {
5970e552da7Schristos   uint64_t val;
5980e552da7Schristos   char buf[1024];
5990e552da7Schristos   FILE* fp;
6000e552da7Schristos 
6010e552da7Schristos   snprintf(buf,
6020e552da7Schristos            sizeof(buf),
6030e552da7Schristos            "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
6040e552da7Schristos            cpunum);
6050e552da7Schristos 
6060e552da7Schristos   fp = uv__open_file(buf);
6070e552da7Schristos   if (fp == NULL)
6080e552da7Schristos     return 0;
6090e552da7Schristos 
6100e552da7Schristos   if (fscanf(fp, "%" PRIu64, &val) != 1)
6110e552da7Schristos     val = 0;
6120e552da7Schristos 
6130e552da7Schristos   fclose(fp);
6140e552da7Schristos 
6150e552da7Schristos   return val;
6160e552da7Schristos }
6170e552da7Schristos 
6180e552da7Schristos 
619*5f2f4271Schristos #ifdef HAVE_IFADDRS_H
uv__ifaddr_exclude(struct ifaddrs * ent,int exclude_type)6200e552da7Schristos static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
6210e552da7Schristos   if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
6220e552da7Schristos     return 1;
6230e552da7Schristos   if (ent->ifa_addr == NULL)
6240e552da7Schristos     return 1;
6250e552da7Schristos   /*
6260e552da7Schristos    * On Linux getifaddrs returns information related to the raw underlying
6270e552da7Schristos    * devices. We're not interested in this information yet.
6280e552da7Schristos    */
6290e552da7Schristos   if (ent->ifa_addr->sa_family == PF_PACKET)
6300e552da7Schristos     return exclude_type;
6310e552da7Schristos   return !exclude_type;
6320e552da7Schristos }
633*5f2f4271Schristos #endif
6340e552da7Schristos 
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)6350e552da7Schristos int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
6360e552da7Schristos #ifndef HAVE_IFADDRS_H
6370e552da7Schristos   *count = 0;
6380e552da7Schristos   *addresses = NULL;
6390e552da7Schristos   return UV_ENOSYS;
6400e552da7Schristos #else
6410e552da7Schristos   struct ifaddrs *addrs, *ent;
6420e552da7Schristos   uv_interface_address_t* address;
6430e552da7Schristos   int i;
6440e552da7Schristos   struct sockaddr_ll *sll;
6450e552da7Schristos 
6460e552da7Schristos   *count = 0;
6470e552da7Schristos   *addresses = NULL;
6480e552da7Schristos 
6490e552da7Schristos   if (getifaddrs(&addrs))
6500e552da7Schristos     return UV__ERR(errno);
6510e552da7Schristos 
6520e552da7Schristos   /* Count the number of interfaces */
6530e552da7Schristos   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
6540e552da7Schristos     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
6550e552da7Schristos       continue;
6560e552da7Schristos 
6570e552da7Schristos     (*count)++;
6580e552da7Schristos   }
6590e552da7Schristos 
6600e552da7Schristos   if (*count == 0) {
6610e552da7Schristos     freeifaddrs(addrs);
6620e552da7Schristos     return 0;
6630e552da7Schristos   }
6640e552da7Schristos 
6650e552da7Schristos   /* Make sure the memory is initiallized to zero using calloc() */
6660e552da7Schristos   *addresses = uv__calloc(*count, sizeof(**addresses));
6670e552da7Schristos   if (!(*addresses)) {
6680e552da7Schristos     freeifaddrs(addrs);
6690e552da7Schristos     return UV_ENOMEM;
6700e552da7Schristos   }
6710e552da7Schristos 
6720e552da7Schristos   address = *addresses;
6730e552da7Schristos 
6740e552da7Schristos   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
6750e552da7Schristos     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
6760e552da7Schristos       continue;
6770e552da7Schristos 
6780e552da7Schristos     address->name = uv__strdup(ent->ifa_name);
6790e552da7Schristos 
6800e552da7Schristos     if (ent->ifa_addr->sa_family == AF_INET6) {
6810e552da7Schristos       address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
6820e552da7Schristos     } else {
6830e552da7Schristos       address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
6840e552da7Schristos     }
6850e552da7Schristos 
6860e552da7Schristos     if (ent->ifa_netmask->sa_family == AF_INET6) {
6870e552da7Schristos       address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
6880e552da7Schristos     } else {
6890e552da7Schristos       address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
6900e552da7Schristos     }
6910e552da7Schristos 
6920e552da7Schristos     address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
6930e552da7Schristos 
6940e552da7Schristos     address++;
6950e552da7Schristos   }
6960e552da7Schristos 
6970e552da7Schristos   /* Fill in physical addresses for each interface */
6980e552da7Schristos   for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
6990e552da7Schristos     if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
7000e552da7Schristos       continue;
7010e552da7Schristos 
7020e552da7Schristos     address = *addresses;
7030e552da7Schristos 
7040e552da7Schristos     for (i = 0; i < (*count); i++) {
7050e552da7Schristos       size_t namelen = strlen(ent->ifa_name);
7060e552da7Schristos       /* Alias interface share the same physical address */
7070e552da7Schristos       if (strncmp(address->name, ent->ifa_name, namelen) == 0 &&
7080e552da7Schristos           (address->name[namelen] == 0 || address->name[namelen] == ':')) {
7090e552da7Schristos         sll = (struct sockaddr_ll*)ent->ifa_addr;
7100e552da7Schristos         memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
7110e552da7Schristos       }
7120e552da7Schristos       address++;
7130e552da7Schristos     }
7140e552da7Schristos   }
7150e552da7Schristos 
7160e552da7Schristos   freeifaddrs(addrs);
7170e552da7Schristos 
7180e552da7Schristos   return 0;
7190e552da7Schristos #endif
7200e552da7Schristos }
7210e552da7Schristos 
7220e552da7Schristos 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)7230e552da7Schristos void uv_free_interface_addresses(uv_interface_address_t* addresses,
7240e552da7Schristos   int count) {
7250e552da7Schristos   int i;
7260e552da7Schristos 
7270e552da7Schristos   for (i = 0; i < count; i++) {
7280e552da7Schristos     uv__free(addresses[i].name);
7290e552da7Schristos   }
7300e552da7Schristos 
7310e552da7Schristos   uv__free(addresses);
7320e552da7Schristos }
7330e552da7Schristos 
7340e552da7Schristos 
uv__set_process_title(const char * title)7350e552da7Schristos void uv__set_process_title(const char* title) {
7360e552da7Schristos #if defined(PR_SET_NAME)
7370e552da7Schristos   prctl(PR_SET_NAME, title);  /* Only copies first 16 characters. */
7380e552da7Schristos #endif
7390e552da7Schristos }
7400e552da7Schristos 
7410e552da7Schristos 
uv__read_proc_meminfo(const char * what)7420e552da7Schristos static uint64_t uv__read_proc_meminfo(const char* what) {
7430e552da7Schristos   uint64_t rc;
7440e552da7Schristos   char* p;
7450e552da7Schristos   char buf[4096];  /* Large enough to hold all of /proc/meminfo. */
7460e552da7Schristos 
747*5f2f4271Schristos   if (uv__slurp("/proc/meminfo", buf, sizeof(buf)))
7480e552da7Schristos     return 0;
7490e552da7Schristos 
7500e552da7Schristos   p = strstr(buf, what);
7510e552da7Schristos 
7520e552da7Schristos   if (p == NULL)
753*5f2f4271Schristos     return 0;
7540e552da7Schristos 
7550e552da7Schristos   p += strlen(what);
7560e552da7Schristos 
757*5f2f4271Schristos   rc = 0;
758*5f2f4271Schristos   sscanf(p, "%" PRIu64 " kB", &rc);
7590e552da7Schristos 
760*5f2f4271Schristos   return rc * 1024;
7610e552da7Schristos }
7620e552da7Schristos 
7630e552da7Schristos 
uv_get_free_memory(void)7640e552da7Schristos uint64_t uv_get_free_memory(void) {
7650e552da7Schristos   struct sysinfo info;
7660e552da7Schristos   uint64_t rc;
7670e552da7Schristos 
768*5f2f4271Schristos   rc = uv__read_proc_meminfo("MemAvailable:");
7690e552da7Schristos 
7700e552da7Schristos   if (rc != 0)
7710e552da7Schristos     return rc;
7720e552da7Schristos 
7730e552da7Schristos   if (0 == sysinfo(&info))
7740e552da7Schristos     return (uint64_t) info.freeram * info.mem_unit;
7750e552da7Schristos 
7760e552da7Schristos   return 0;
7770e552da7Schristos }
7780e552da7Schristos 
7790e552da7Schristos 
uv_get_total_memory(void)7800e552da7Schristos uint64_t uv_get_total_memory(void) {
7810e552da7Schristos   struct sysinfo info;
7820e552da7Schristos   uint64_t rc;
7830e552da7Schristos 
7840e552da7Schristos   rc = uv__read_proc_meminfo("MemTotal:");
7850e552da7Schristos 
7860e552da7Schristos   if (rc != 0)
7870e552da7Schristos     return rc;
7880e552da7Schristos 
7890e552da7Schristos   if (0 == sysinfo(&info))
7900e552da7Schristos     return (uint64_t) info.totalram * info.mem_unit;
7910e552da7Schristos 
7920e552da7Schristos   return 0;
7930e552da7Schristos }
7940e552da7Schristos 
7950e552da7Schristos 
uv__read_cgroups_uint64(const char * cgroup,const char * param)7960e552da7Schristos static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
7970e552da7Schristos   char filename[256];
7980e552da7Schristos   char buf[32];  /* Large enough to hold an encoded uint64_t. */
799*5f2f4271Schristos   uint64_t rc;
8000e552da7Schristos 
8010e552da7Schristos   rc = 0;
802*5f2f4271Schristos   snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param);
803*5f2f4271Schristos   if (0 == uv__slurp(filename, buf, sizeof(buf)))
8040e552da7Schristos     sscanf(buf, "%" PRIu64, &rc);
8050e552da7Schristos 
8060e552da7Schristos   return rc;
8070e552da7Schristos }
8080e552da7Schristos 
8090e552da7Schristos 
uv_get_constrained_memory(void)8100e552da7Schristos uint64_t uv_get_constrained_memory(void) {
8110e552da7Schristos   /*
8120e552da7Schristos    * This might return 0 if there was a problem getting the memory limit from
8130e552da7Schristos    * cgroups. This is OK because a return value of 0 signifies that the memory
8140e552da7Schristos    * limit is unknown.
8150e552da7Schristos    */
8160e552da7Schristos   return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
8170e552da7Schristos }
818*5f2f4271Schristos 
819*5f2f4271Schristos 
uv_loadavg(double avg[3])820*5f2f4271Schristos void uv_loadavg(double avg[3]) {
821*5f2f4271Schristos   struct sysinfo info;
822*5f2f4271Schristos   char buf[128];  /* Large enough to hold all of /proc/loadavg. */
823*5f2f4271Schristos 
824*5f2f4271Schristos   if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
825*5f2f4271Schristos     if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
826*5f2f4271Schristos       return;
827*5f2f4271Schristos 
828*5f2f4271Schristos   if (sysinfo(&info) < 0)
829*5f2f4271Schristos     return;
830*5f2f4271Schristos 
831*5f2f4271Schristos   avg[0] = (double) info.loads[0] / 65536.0;
832*5f2f4271Schristos   avg[1] = (double) info.loads[1] / 65536.0;
833*5f2f4271Schristos   avg[2] = (double) info.loads[2] / 65536.0;
834*5f2f4271Schristos }
835