library: become more tolerant of /proc/cpuinfo formats

In the issue referenced below, it is now apparent that
not all architectures follow a logical/expected format
for the /proc/cpuinfo file. Specifically, the expected
empty line after each processor entry might be missing
under some architectures for the last processor shown.

[ and a belated review of kernel source confirms it. ]

So this commit makes our stat module a little bit more
tolerant of some potential missing newline characters.

[ along the way, it's also now tolerant of a missing ]
[ cpuinfo file plus more efficient whenever a cpu is ]
[ is not linked to a core or toggled offline/online. ]

Reference(s):
https://gitlab.com/procps-ng/procps/-/issues/272
procps-ng/procps#272

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2023-03-01 00:00:00 -06:00 committed by Craig Small
parent 8c81808de0
commit 133a833942

View File

@ -515,8 +515,9 @@ static int stat_cores_verify (
int a_cpu, a_core; int a_cpu, a_core;
FILE *fp; FILE *fp;
// be tolerant of a missing CORE_FILE ...
if (!(fp = fopen(CORE_FILE, "r"))) if (!(fp = fopen(CORE_FILE, "r")))
return 0; return 1;
for (;;) { for (;;) {
if (NULL == fgets(buf, sizeof(buf), fp)) if (NULL == fgets(buf, sizeof(buf), fp))
break; break;
@ -525,12 +526,11 @@ static int stat_cores_verify (
continue; continue;
sscanf(buf, "processor : %d", &a_cpu); sscanf(buf, "processor : %d", &a_cpu);
for (;;) { for (;;) {
if (NULL == fgets(buf, sizeof(buf), fp)) { // be tolerant of missing empty line on last processor entry ...
fclose(fp); if (NULL == fgets(buf, sizeof(buf), fp))
errno = EIO; goto wrap_up;
return 0; // be tolerant of a missing 'core id' on any processor entry ...
} if (buf[0] == '\n') {
if (buf[0] == '\n') { /* Entry for specific processor is finished */
a_core = a_cpu; a_core = a_cpu;
break; break;
} }
@ -545,6 +545,7 @@ static int stat_cores_verify (
return 0; return 0;
} }
} }
wrap_up:
fclose(fp); fclose(fp);
stat_cores_check(info); stat_cores_check(info);
return 1; return 1;
@ -785,6 +786,8 @@ reap_em_again:
cpu_ptr = info->cpus.hist.tics + i; // adapt to relocated if reap_em_again cpu_ptr = info->cpus.hist.tics + i; // adapt to relocated if reap_em_again
do { do {
static int once_sw;
bp = 1 + strchr(bp, '\n'); bp = 1 + strchr(bp, '\n');
// remember this cpu from last time around // remember this cpu from last time around
memcpy(&cpu_ptr->old, &cpu_ptr->new, sizeof(struct stat_jifs)); memcpy(&cpu_ptr->old, &cpu_ptr->new, sizeof(struct stat_jifs));
@ -806,14 +809,17 @@ reap_em_again:
} }
stat_derive_unique(cpu_ptr); stat_derive_unique(cpu_ptr);
// force a one time core link for cpu0 (if possible) ...
if (!once_sw)
once_sw = cpu_ptr->saved_id = -1;
/* this happens if cpus are taken offline/brought back online /* this happens if cpus are taken offline/brought back online
so we better force the proper current core association ... */ so we better force the proper current core association ... */
if (cpu_ptr->saved_id != cpu_ptr->id) { if (cpu_ptr->saved_id != cpu_ptr->id) {
cpu_ptr->saved_id = cpu_ptr->id; cpu_ptr->saved_id = cpu_ptr->id;
cpu_ptr->core = NULL; cpu_ptr->core = NULL;
}
if (!cpu_ptr->core)
stat_cores_link(info, cpu_ptr); stat_cores_link(info, cpu_ptr);
}
#ifdef CPU_IDLE_FORCED #ifdef CPU_IDLE_FORCED
// first time through (that priming read) sum_ptr->edge will be zero | // first time through (that priming read) sum_ptr->edge will be zero |