linux: fix cpu count

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é <saghul@gmail.com>
This commit is contained in:
Lukasz Jagiello 2016-02-25 07:29:18 +00:00 committed by Saúl Ibarra Corretgé
parent ca0b657891
commit 6798876a6b

View File

@ -69,7 +69,7 @@
#endif #endif
static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); 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 void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
static unsigned long read_cpufreq(unsigned int cpunum); 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) { int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
unsigned int numcpus; unsigned int numcpus;
uv_cpu_info_t* ci; uv_cpu_info_t* ci;
int err; int err;
int statfile_fd;
FILE* statfile_fp;
*cpu_infos = NULL; *cpu_infos = NULL;
*count = 0; *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 != (unsigned int) -1);
assert(numcpus != 0); assert(numcpus != 0);
@ -570,7 +603,10 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
err = read_models(numcpus, ci); err = read_models(numcpus, ci);
if (err == 0) if (err == 0)
err = read_times(numcpus, ci); rewind(statfile_fp);
err = read_times(statfile_fp, numcpus, ci);
uv__close(statfile_fd);
if (err) { if (err) {
uv_free_cpu_info(ci, numcpus); 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; unsigned long clock_ticks;
struct uv_cpu_times_s ts; struct uv_cpu_times_s ts;
unsigned long user; unsigned long user;
@ -708,22 +744,19 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
unsigned int num; unsigned int num;
unsigned int len; unsigned int len;
char buf[1024]; char buf[1024];
FILE* fp;
clock_ticks = sysconf(_SC_CLK_TCK); clock_ticks = sysconf(_SC_CLK_TCK);
assert(clock_ticks != (unsigned long) -1); assert(clock_ticks != (unsigned long) -1);
assert(clock_ticks != 0); assert(clock_ticks != 0);
fp = fopen("/proc/stat", "r"); rewind(statfile_fp);
if (fp == NULL)
return -errno;
if (!fgets(buf, sizeof(buf), fp)) if (!fgets(buf, sizeof(buf), statfile_fp))
abort(); abort();
num = 0; num = 0;
while (fgets(buf, sizeof(buf), fp)) { while (fgets(buf, sizeof(buf), statfile_fp)) {
if (num >= numcpus) if (num >= numcpus)
break; break;
@ -762,7 +795,6 @@ static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
ts.irq = clock_ticks * irq; ts.irq = clock_ticks * irq;
ci[num++].cpu_times = ts; ci[num++].cpu_times = ts;
} }
fclose(fp);
assert(num == numcpus); assert(num == numcpus);
return 0; return 0;