Path: blob/master/Utilities/cmlibuv/src/unix/linux-core.c
3156 views
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.1* Permission is hereby granted, free of charge, to any person obtaining a copy2* of this software and associated documentation files (the "Software"), to3* deal in the Software without restriction, including without limitation the4* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or5* sell copies of the Software, and to permit persons to whom the Software is6* furnished to do so, subject to the following conditions:7*8* The above copyright notice and this permission notice shall be included in9* all copies or substantial portions of the Software.10*11* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR12* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,13* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE14* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER15* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING16* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS17* IN THE SOFTWARE.18*/1920/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their21* EPOLL* counterparts. We use the POLL* variants in this file because that22* is what libuv uses elsewhere.23*/2425#include "uv.h"26#include "internal.h"2728#include <inttypes.h>29#include <stdint.h>30#include <stdio.h>31#include <stdlib.h>32#include <string.h>33#include <assert.h>34#include <errno.h>3536#include <net/if.h>37#include <sys/epoll.h>38#include <sys/param.h>39#include <sys/prctl.h>40#include <sys/sysinfo.h>41#include <unistd.h>42#include <fcntl.h>43#include <time.h>4445#define HAVE_IFADDRS_H 14647# if defined(__ANDROID_API__) && __ANDROID_API__ < 2448# undef HAVE_IFADDRS_H49#endif5051#ifdef __UCLIBC__52# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 3253# undef HAVE_IFADDRS_H54# endif55#endif5657#ifdef HAVE_IFADDRS_H58# include <ifaddrs.h>59# include <sys/socket.h>60# include <net/ethernet.h>61# include <netpacket/packet.h>62#endif /* HAVE_IFADDRS_H */6364/* Available from 2.6.32 onwards. */65#ifndef CLOCK_MONOTONIC_COARSE66# define CLOCK_MONOTONIC_COARSE 667#endif6869/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't70* include that file because it conflicts with <time.h>. We'll just have to71* define it ourselves.72*/73#ifndef CLOCK_BOOTTIME74# define CLOCK_BOOTTIME 775#endif7677static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);78static int read_times(FILE* statfile_fp,79unsigned int numcpus,80uv_cpu_info_t* ci);81static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);82static uint64_t read_cpufreq(unsigned int cpunum);8384int uv__platform_loop_init(uv_loop_t* loop) {8586loop->inotify_fd = -1;87loop->inotify_watchers = NULL;8889return uv__epoll_init(loop);90}919293int uv__io_fork(uv_loop_t* loop) {94int err;95void* old_watchers;9697old_watchers = loop->inotify_watchers;9899uv__close(loop->backend_fd);100loop->backend_fd = -1;101uv__platform_loop_delete(loop);102103err = uv__platform_loop_init(loop);104if (err)105return err;106107return uv__inotify_fork(loop, old_watchers);108}109110111void uv__platform_loop_delete(uv_loop_t* loop) {112if (loop->inotify_fd == -1) return;113uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);114uv__close(loop->inotify_fd);115loop->inotify_fd = -1;116}117118119120uint64_t uv__hrtime(uv_clocktype_t type) {121static clock_t fast_clock_id = -1;122struct timespec t;123clock_t clock_id;124125/* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has126* millisecond granularity or better. CLOCK_MONOTONIC_COARSE is127* serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may128* decide to make a costly system call.129*/130/* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE131* when it has microsecond granularity or better (unlikely).132*/133clock_id = CLOCK_MONOTONIC;134if (type != UV_CLOCK_FAST)135goto done;136137clock_id = uv__load_relaxed(&fast_clock_id);138if (clock_id != -1)139goto done;140141clock_id = CLOCK_MONOTONIC;142if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t))143if (t.tv_nsec <= 1 * 1000 * 1000)144clock_id = CLOCK_MONOTONIC_COARSE;145146uv__store_relaxed(&fast_clock_id, clock_id);147148done:149150if (clock_gettime(clock_id, &t))151return 0; /* Not really possible. */152153return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;154}155156157int uv_resident_set_memory(size_t* rss) {158char buf[1024];159const char* s;160ssize_t n;161long val;162int fd;163int i;164165do166fd = open("/proc/self/stat", O_RDONLY);167while (fd == -1 && errno == EINTR);168169if (fd == -1)170return UV__ERR(errno);171172do173n = read(fd, buf, sizeof(buf) - 1);174while (n == -1 && errno == EINTR);175176uv__close(fd);177if (n == -1)178return UV__ERR(errno);179buf[n] = '\0';180181s = strchr(buf, ' ');182if (s == NULL)183goto err;184185s += 1;186if (*s != '(')187goto err;188189s = strchr(s, ')');190if (s == NULL)191goto err;192193for (i = 1; i <= 22; i++) {194s = strchr(s + 1, ' ');195if (s == NULL)196goto err;197}198199errno = 0;200val = strtol(s, NULL, 10);201if (errno != 0)202goto err;203if (val < 0)204goto err;205206*rss = val * getpagesize();207return 0;208209err:210return UV_EINVAL;211}212213int uv_uptime(double* uptime) {214static volatile int no_clock_boottime;215char buf[128];216struct timespec now;217int r;218219/* Try /proc/uptime first, then fallback to clock_gettime(). */220221if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))222if (1 == sscanf(buf, "%lf", uptime))223return 0;224225/* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available226* (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system227* is suspended.228*/229if (no_clock_boottime) {230retry_clock_gettime: r = clock_gettime(CLOCK_MONOTONIC, &now);231}232else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {233no_clock_boottime = 1;234goto retry_clock_gettime;235}236237if (r)238return UV__ERR(errno);239240*uptime = now.tv_sec;241return 0;242}243244245static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {246unsigned int num;247char buf[1024];248249if (!fgets(buf, sizeof(buf), statfile_fp))250return UV_EIO;251252num = 0;253while (fgets(buf, sizeof(buf), statfile_fp)) {254if (strncmp(buf, "cpu", 3))255break;256num++;257}258259if (num == 0)260return UV_EIO;261262*numcpus = num;263return 0;264}265266267int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {268unsigned int numcpus;269uv_cpu_info_t* ci;270int err;271FILE* statfile_fp;272273*cpu_infos = NULL;274*count = 0;275276statfile_fp = uv__open_file("/proc/stat");277if (statfile_fp == NULL)278return UV__ERR(errno);279280err = uv__cpu_num(statfile_fp, &numcpus);281if (err < 0)282goto out;283284err = UV_ENOMEM;285ci = uv__calloc(numcpus, sizeof(*ci));286if (ci == NULL)287goto out;288289err = read_models(numcpus, ci);290if (err == 0)291err = read_times(statfile_fp, numcpus, ci);292293if (err) {294uv_free_cpu_info(ci, numcpus);295goto out;296}297298/* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.299* We don't check for errors here. Worst case, the field is left zero.300*/301if (ci[0].speed == 0)302read_speeds(numcpus, ci);303304*cpu_infos = ci;305*count = numcpus;306err = 0;307308out:309310if (fclose(statfile_fp))311if (errno != EINTR && errno != EINPROGRESS)312abort();313314return err;315}316317318static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {319unsigned int num;320321for (num = 0; num < numcpus; num++)322ci[num].speed = read_cpufreq(num) / 1000;323}324325326/* Also reads the CPU frequency on ppc and x86. The other architectures only327* have a BogoMIPS field, which may not be very accurate.328*329* Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.330*/331static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {332#if defined(__PPC__)333static const char model_marker[] = "cpu\t\t: ";334static const char speed_marker[] = "clock\t\t: ";335#else336static const char model_marker[] = "model name\t: ";337static const char speed_marker[] = "cpu MHz\t\t: ";338#endif339const char* inferred_model;340unsigned int model_idx;341unsigned int speed_idx;342unsigned int part_idx;343char buf[1024];344char* model;345FILE* fp;346int model_id;347348/* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */349(void) &model_marker;350(void) &speed_marker;351(void) &speed_idx;352(void) &part_idx;353(void) &model;354(void) &buf;355(void) &fp;356(void) &model_id;357358model_idx = 0;359speed_idx = 0;360part_idx = 0;361362#if defined(__arm__) || \363defined(__i386__) || \364defined(__mips__) || \365defined(__aarch64__) || \366defined(__PPC__) || \367defined(__x86_64__)368fp = uv__open_file("/proc/cpuinfo");369if (fp == NULL)370return UV__ERR(errno);371372while (fgets(buf, sizeof(buf), fp)) {373if (model_idx < numcpus) {374if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {375model = buf + sizeof(model_marker) - 1;376model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */377if (model == NULL) {378fclose(fp);379return UV_ENOMEM;380}381ci[model_idx++].model = model;382continue;383}384}385#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)386if (model_idx < numcpus) {387#if defined(__arm__)388/* Fallback for pre-3.8 kernels. */389static const char model_marker[] = "Processor\t: ";390#elif defined(__aarch64__)391static const char part_marker[] = "CPU part\t: ";392393/* Adapted from: https://github.com/karelzak/util-linux */394struct vendor_part {395const int id;396const char* name;397};398399static const struct vendor_part arm_chips[] = {400{ 0x811, "ARM810" },401{ 0x920, "ARM920" },402{ 0x922, "ARM922" },403{ 0x926, "ARM926" },404{ 0x940, "ARM940" },405{ 0x946, "ARM946" },406{ 0x966, "ARM966" },407{ 0xa20, "ARM1020" },408{ 0xa22, "ARM1022" },409{ 0xa26, "ARM1026" },410{ 0xb02, "ARM11 MPCore" },411{ 0xb36, "ARM1136" },412{ 0xb56, "ARM1156" },413{ 0xb76, "ARM1176" },414{ 0xc05, "Cortex-A5" },415{ 0xc07, "Cortex-A7" },416{ 0xc08, "Cortex-A8" },417{ 0xc09, "Cortex-A9" },418{ 0xc0d, "Cortex-A17" }, /* Originally A12 */419{ 0xc0f, "Cortex-A15" },420{ 0xc0e, "Cortex-A17" },421{ 0xc14, "Cortex-R4" },422{ 0xc15, "Cortex-R5" },423{ 0xc17, "Cortex-R7" },424{ 0xc18, "Cortex-R8" },425{ 0xc20, "Cortex-M0" },426{ 0xc21, "Cortex-M1" },427{ 0xc23, "Cortex-M3" },428{ 0xc24, "Cortex-M4" },429{ 0xc27, "Cortex-M7" },430{ 0xc60, "Cortex-M0+" },431{ 0xd01, "Cortex-A32" },432{ 0xd03, "Cortex-A53" },433{ 0xd04, "Cortex-A35" },434{ 0xd05, "Cortex-A55" },435{ 0xd06, "Cortex-A65" },436{ 0xd07, "Cortex-A57" },437{ 0xd08, "Cortex-A72" },438{ 0xd09, "Cortex-A73" },439{ 0xd0a, "Cortex-A75" },440{ 0xd0b, "Cortex-A76" },441{ 0xd0c, "Neoverse-N1" },442{ 0xd0d, "Cortex-A77" },443{ 0xd0e, "Cortex-A76AE" },444{ 0xd13, "Cortex-R52" },445{ 0xd20, "Cortex-M23" },446{ 0xd21, "Cortex-M33" },447{ 0xd41, "Cortex-A78" },448{ 0xd42, "Cortex-A78AE" },449{ 0xd4a, "Neoverse-E1" },450{ 0xd4b, "Cortex-A78C" },451};452453if (strncmp(buf, part_marker, sizeof(part_marker) - 1) == 0) {454model = buf + sizeof(part_marker) - 1;455456errno = 0;457model_id = strtol(model, NULL, 16);458if ((errno != 0) || model_id < 0) {459fclose(fp);460return UV_EINVAL;461}462463for (part_idx = 0; part_idx < ARRAY_SIZE(arm_chips); part_idx++) {464if (model_id == arm_chips[part_idx].id) {465model = uv__strdup(arm_chips[part_idx].name);466if (model == NULL) {467fclose(fp);468return UV_ENOMEM;469}470ci[model_idx++].model = model;471break;472}473}474}475#else /* defined(__mips__) */476static const char model_marker[] = "cpu model\t\t: ";477#endif478if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {479model = buf + sizeof(model_marker) - 1;480model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */481if (model == NULL) {482fclose(fp);483return UV_ENOMEM;484}485ci[model_idx++].model = model;486continue;487}488}489#else /* !__arm__ && !__mips__ && !__aarch64__ */490if (speed_idx < numcpus) {491if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {492ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);493continue;494}495}496#endif /* __arm__ || __mips__ || __aarch64__ */497}498499fclose(fp);500#endif /* __arm__ || __i386__ || __mips__ || __PPC__ || __x86_64__ || __aarch__ */501502/* Now we want to make sure that all the models contain *something* because503* it's not safe to leave them as null. Copy the last entry unless there504* isn't one, in that case we simply put "unknown" into everything.505*/506inferred_model = "unknown";507if (model_idx > 0)508inferred_model = ci[model_idx - 1].model;509510while (model_idx < numcpus) {511model = uv__strndup(inferred_model, strlen(inferred_model));512if (model == NULL)513return UV_ENOMEM;514ci[model_idx++].model = model;515}516517return 0;518}519520521static int read_times(FILE* statfile_fp,522unsigned int numcpus,523uv_cpu_info_t* ci) {524struct uv_cpu_times_s ts;525unsigned int ticks;526unsigned int multiplier;527uint64_t user;528uint64_t nice;529uint64_t sys;530uint64_t idle;531uint64_t dummy;532uint64_t irq;533uint64_t num;534uint64_t len;535char buf[1024];536537ticks = (unsigned int)sysconf(_SC_CLK_TCK);538assert(ticks != (unsigned int) -1);539assert(ticks != 0);540multiplier = ((uint64_t)1000L / ticks);541542rewind(statfile_fp);543544if (!fgets(buf, sizeof(buf), statfile_fp))545abort();546547num = 0;548549while (fgets(buf, sizeof(buf), statfile_fp)) {550if (num >= numcpus)551break;552553if (strncmp(buf, "cpu", 3))554break;555556/* skip "cpu<num> " marker */557{558unsigned int n;559int r = sscanf(buf, "cpu%u ", &n);560assert(r == 1);561(void) r; /* silence build warning */562for (len = sizeof("cpu0"); n /= 10; len++);563}564565/* Line contains user, nice, system, idle, iowait, irq, softirq, steal,566* guest, guest_nice but we're only interested in the first four + irq.567*568* Don't use %*s to skip fields or %ll to read straight into the uint64_t569* fields, they're not allowed in C89 mode.570*/571if (6 != sscanf(buf + len,572"%" PRIu64 " %" PRIu64 " %" PRIu64573"%" PRIu64 " %" PRIu64 " %" PRIu64,574&user,575&nice,576&sys,577&idle,578&dummy,579&irq))580abort();581582ts.user = user * multiplier;583ts.nice = nice * multiplier;584ts.sys = sys * multiplier;585ts.idle = idle * multiplier;586ts.irq = irq * multiplier;587ci[num++].cpu_times = ts;588}589assert(num == numcpus);590591return 0;592}593594595static uint64_t read_cpufreq(unsigned int cpunum) {596uint64_t val;597char buf[1024];598FILE* fp;599600snprintf(buf,601sizeof(buf),602"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",603cpunum);604605fp = uv__open_file(buf);606if (fp == NULL)607return 0;608609if (fscanf(fp, "%" PRIu64, &val) != 1)610val = 0;611612fclose(fp);613614return val;615}616617618#ifdef HAVE_IFADDRS_H619static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {620if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))621return 1;622if (ent->ifa_addr == NULL)623return 1;624/*625* On Linux getifaddrs returns information related to the raw underlying626* devices. We're not interested in this information yet.627*/628if (ent->ifa_addr->sa_family == PF_PACKET)629return exclude_type;630return !exclude_type;631}632#endif633634int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {635#ifndef HAVE_IFADDRS_H636*count = 0;637*addresses = NULL;638return UV_ENOSYS;639#else640struct ifaddrs *addrs, *ent;641uv_interface_address_t* address;642int i;643struct sockaddr_ll *sll;644645*count = 0;646*addresses = NULL;647648if (getifaddrs(&addrs))649return UV__ERR(errno);650651/* Count the number of interfaces */652for (ent = addrs; ent != NULL; ent = ent->ifa_next) {653if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))654continue;655656(*count)++;657}658659if (*count == 0) {660freeifaddrs(addrs);661return 0;662}663664/* Make sure the memory is initiallized to zero using calloc() */665*addresses = uv__calloc(*count, sizeof(**addresses));666if (!(*addresses)) {667freeifaddrs(addrs);668return UV_ENOMEM;669}670671address = *addresses;672673for (ent = addrs; ent != NULL; ent = ent->ifa_next) {674if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))675continue;676677address->name = uv__strdup(ent->ifa_name);678679if (ent->ifa_addr->sa_family == AF_INET6) {680address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);681} else {682address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);683}684685if (ent->ifa_netmask->sa_family == AF_INET6) {686address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);687} else {688address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);689}690691address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);692693address++;694}695696/* Fill in physical addresses for each interface */697for (ent = addrs; ent != NULL; ent = ent->ifa_next) {698if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))699continue;700701address = *addresses;702703for (i = 0; i < (*count); i++) {704size_t namelen = strlen(ent->ifa_name);705/* Alias interface share the same physical address */706if (strncmp(address->name, ent->ifa_name, namelen) == 0 &&707(address->name[namelen] == 0 || address->name[namelen] == ':')) {708sll = (struct sockaddr_ll*)ent->ifa_addr;709memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));710}711address++;712}713}714715freeifaddrs(addrs);716717return 0;718#endif719}720721722void uv_free_interface_addresses(uv_interface_address_t* addresses,723int count) {724int i;725726for (i = 0; i < count; i++) {727uv__free(addresses[i].name);728}729730uv__free(addresses);731}732733734void uv__set_process_title(const char* title) {735#if defined(PR_SET_NAME)736prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */737#endif738}739740741static uint64_t uv__read_proc_meminfo(const char* what) {742uint64_t rc;743char* p;744char buf[4096]; /* Large enough to hold all of /proc/meminfo. */745746if (uv__slurp("/proc/meminfo", buf, sizeof(buf)))747return 0;748749p = strstr(buf, what);750751if (p == NULL)752return 0;753754p += strlen(what);755756rc = 0;757sscanf(p, "%" PRIu64 " kB", &rc);758759return rc * 1024;760}761762763uint64_t uv_get_free_memory(void) {764struct sysinfo info;765uint64_t rc;766767rc = uv__read_proc_meminfo("MemAvailable:");768769if (rc != 0)770return rc;771772if (0 == sysinfo(&info))773return (uint64_t) info.freeram * info.mem_unit;774775return 0;776}777778779uint64_t uv_get_total_memory(void) {780struct sysinfo info;781uint64_t rc;782783rc = uv__read_proc_meminfo("MemTotal:");784785if (rc != 0)786return rc;787788if (0 == sysinfo(&info))789return (uint64_t) info.totalram * info.mem_unit;790791return 0;792}793794795static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {796char filename[256];797char buf[32]; /* Large enough to hold an encoded uint64_t. */798uint64_t rc;799800rc = 0;801snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%s/%s", cgroup, param);802if (0 == uv__slurp(filename, buf, sizeof(buf)))803sscanf(buf, "%" PRIu64, &rc);804805return rc;806}807808809uint64_t uv_get_constrained_memory(void) {810/*811* This might return 0 if there was a problem getting the memory limit from812* cgroups. This is OK because a return value of 0 signifies that the memory813* limit is unknown.814*/815return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");816}817818819void uv_loadavg(double avg[3]) {820struct sysinfo info;821char buf[128]; /* Large enough to hold all of /proc/loadavg. */822823if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))824if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))825return;826827if (sysinfo(&info) < 0)828return;829830avg[0] = (double) info.loads[0] / 65536.0;831avg[1] = (double) info.loads[1] / 65536.0;832avg[2] = (double) info.loads[2] / 65536.0;833}834835836