]> granicus.if.org Git - procps-ng/commitdiff
library: become more tolerant of /proc/cpuinfo formats
authorJim Warner <james.warner@comcast.net>
Wed, 1 Mar 2023 06:00:00 +0000 (00:00 -0600)
committerCraig Small <csmall@dropbear.xyz>
Thu, 2 Mar 2023 08:38:41 +0000 (19:38 +1100)
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>
library/stat.c

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