From 6798876a6b2c2046d926bd2317284de920e6d124 Mon Sep 17 00:00:00 2001 From: Lukasz Jagiello Date: Thu, 25 Feb 2016 07:29:18 +0000 Subject: [PATCH] linux: fix cpu count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When libuv is running inside container - eg. lxc container, cpu number is not obvious. Linux control groups (cgroups) may limit numer of cpus. As a result of different number cpu cores inside container and outside container, libuv is crashing. sysconf(_SC_NPROCESSORS_ONLN) - returns num of host cpus (eg. 32) `/proc/stat` - sees only cpus limited by cgroups (eg. 4) When libuv is trying to operate at both numbers and they're different it's crashing with current test: run-tests: ../src/unix/linux-core.c:766: read_times: Assertion `num == numcpus' failed. Count the number of cpus based on `/proc/stat` instead. PR-URL: https://github.com/libuv/libuv/pull/735 Reviewed-By: Saúl Ibarra Corretgé --- src/unix/linux-core.c | 54 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index a303b21bc..1fdd71d0f 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -69,7 +69,7 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static unsigned long read_cpufreq(unsigned int cpunum); @@ -552,15 +552,48 @@ int uv_uptime(double* uptime) { } +static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { + unsigned int num; + char buf[1024]; + + if (!fgets(buf, sizeof(buf), statfile_fp)) + abort(); + + num = 0; + while (fgets(buf, sizeof(buf), statfile_fp)) { + if (strncmp(buf, "cpu", 3)) + break; + num++; + } + + *numcpus = num; + return 0; +} + + int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { unsigned int numcpus; uv_cpu_info_t* ci; int err; + int statfile_fd; + FILE* statfile_fp; *cpu_infos = NULL; *count = 0; - numcpus = sysconf(_SC_NPROCESSORS_ONLN); + err = uv__open_cloexec("/proc/stat", O_RDONLY); + if (err < 0) + return err; + statfile_fd = err; + + statfile_fp = fdopen(statfile_fd, "r"); + if (statfile_fp == NULL) + return -errno; + + err = uv__cpu_num(statfile_fp, &numcpus); + if (err < 0) + return err; + assert(numcpus != (unsigned int) -1); assert(numcpus != 0); @@ -570,7 +603,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = read_models(numcpus, ci); if (err == 0) - err = read_times(numcpus, ci); + rewind(statfile_fp); + err = read_times(statfile_fp, numcpus, ci); + + uv__close(statfile_fd); if (err) { uv_free_cpu_info(ci, numcpus); @@ -696,7 +732,7 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; @@ -708,22 +744,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { unsigned int num; unsigned int len; char buf[1024]; - FILE* fp; clock_ticks = sysconf(_SC_CLK_TCK); assert(clock_ticks != (unsigned long) -1); assert(clock_ticks != 0); - fp = fopen("/proc/stat", "r"); - if (fp == NULL) - return -errno; + rewind(statfile_fp); - if (!fgets(buf, sizeof(buf), fp)) + if (!fgets(buf, sizeof(buf), statfile_fp)) abort(); num = 0; - while (fgets(buf, sizeof(buf), fp)) { + while (fgets(buf, sizeof(buf), statfile_fp)) { if (num >= numcpus) break; @@ -762,7 +795,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) { ts.irq = clock_ticks * irq; ci[num++].cpu_times = ts; } - fclose(fp); assert(num == numcpus); return 0;