fix(Memory): fix reading procfs files and simplify data parsing

Files in procfs are always changed by kernel.

It means if we read the data with more than one read syscall,
we could get an incorrect data which was broken by kernel.

A typical case about this problem was reported by psutil in
https://github.com/giampaolo/psutil/issues/2050

Using an big buffer let read reads the whole file can fix this.
psutil uses a 32K buffer while procps-ng uses a 8K buffer, i think a 8K buffer is enough.
This commit is contained in:
apocelipes
2023-12-04 16:47:00 +09:00
committed by Carter Li
parent 182c90b22c
commit 6eae425679
2 changed files with 27 additions and 30 deletions
+4
View File
@@ -11,6 +11,10 @@
#include <unistd.h>
#include <dirent.h>
typedef int FFNativeFD;
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
// one safe way to read correct data is reading the whole file in a single read syscall
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
#define PROC_FILE_BUFFSIZ 8192
#endif
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
+23 -30
View File
@@ -6,12 +6,11 @@
const char* ffDetectMemory(FFMemoryResult* ram)
{
FF_AUTO_CLOSE_FILE FILE* meminfo = fopen("/proc/meminfo", "r");
if(meminfo == NULL)
return "Failed to open /proc/meminfo";
char* FF_AUTO_FREE line = NULL;
size_t len = 0;
char buf[PROC_FILE_BUFFSIZ];
ssize_t nRead = ffReadFileData("/proc/meminfo", sizeof(buf) - 1, buf);
if(nRead < 0)
return "ffReadFileData(\"/proc/meminfo\", sizeof(buf)-1, buf)";
buf[nRead] = '\0';
uint64_t memTotal = 0,
shmem = 0,
@@ -19,32 +18,26 @@ const char* ffDetectMemory(FFMemoryResult* ram)
buffers = 0,
cached = 0,
sReclaimable = 0;
uint8_t count = 0;
char *token = NULL;
if((token = strstr(buf, "MemTotal:")) != NULL)
sscanf(token, "MemTotal: %" PRIu64, &memTotal);
while (getline(&line, &len, meminfo) != EOF)
{
switch (line[0])
{
case 'B':
if (sscanf(line, "Buffers: %" PRIu64, &buffers) > 0)
if (++count >= 6) goto done;
break;
case 'C':
if (sscanf(line, "Cached: %" PRIu64, &cached) > 0)
if (++count >= 6) goto done;
break;
case 'M':
if(sscanf(line, "MemTotal: %" PRIu64, &memTotal) > 0 || sscanf(line, "MemFree: %" PRIu64, &memFree) > 0)
if (++count >= 6) goto done;
break;
case 'S':
if(sscanf(line, "Shmem: %" PRIu64, &shmem) > 0 || sscanf(line, "SReclaimable: %" PRIu64, &sReclaimable) > 0)
if (++count >= 6) goto done;
break;
}
}
if((token = strstr(buf, "MemFree:")) != NULL)
sscanf(token, "MemFree: %" PRIu64, &memFree);
if((token = strstr(buf, "Buffers:")) != NULL)
sscanf(token, "Buffers: %" PRIu64, &buffers);
if((token = strstr(buf, "Cached:")) != NULL)
sscanf(token, "Cached: %" PRIu64, &cached);
if((token = strstr(buf, "Shmem:")) != NULL)
sscanf(token, "Shmem: %" PRIu64, &shmem);
if((token = strstr(buf, "SReclaimable:")) != NULL)
sscanf(token, "SReclaimable: %" PRIu64, &sReclaimable);
done:
ram->bytesTotal = memTotal * 1024lu;
ram->bytesUsed = (memTotal + shmem - memFree - buffers - cached - sReclaimable) * 1024lu;