diff options
author | Kirill Tkhai <tkhai@ya.ru> | 2023-03-31 00:10:40 +0300 |
---|---|---|
committer | BenBE <BenBE@geshi.org> | 2023-03-31 22:39:27 +0200 |
commit | b618c379e13e7a2bb688cd54a64d199a267c0438 (patch) | |
tree | 8af3a91de85685367f60ded5cf6988009e1197fd /linux/LinuxProcessList.c | |
parent | f66f04e6e0e6350ff8ea8242031ad43ce06a0a2b (diff) |
This patch is for "Hide userland process threads mode is off" case.
Below is a small example of two threads program, whose main thread
statistics is incorrect in htop. Despite main thread is permanently
sleeping, its CPU load is 100% (must be 0%). CPU load of secondary
thread is correct (100%).
void *thread_func(void *data)
{
while(1) {
}
return NULL;
}
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, thread_func, NULL);
pthread_join(thread, NULL);
}
The reason is in there is a difference in behavior of some files
in /proc/pid and /proc/pid/task/pid directories. For example,
/proc/pid/stat shows agregated user and sys times for all threads
of a process. For the details please see do_task_stat() implementation
and this function behavior difference in dependence of last argument:
https://elixir.bootlin.com/linux/v6.2.8/source/fs/proc/array.c#L652
So, the problem occurs because of user and sys times of main thread are
polluted by secondary thread statistics. This patch fixes the problem
by reading correct stat from /proc/pid/task/pid/stat for main thread.
Looking at other files from /proc/pid directory I found /proc/pid/io
file with the same problem:
https://elixir.bootlin.com/linux/v6.2.8/source/fs/proc/base.c#L3029
This problem is also fixed in this patch by reading correct data
from /proc/pid/task/pid/io file for main thread.
/proc/pid directory files are declared in tgid_base_stuff, while
/proc/pid/task/tid directory files are declared in tid_base_stuff
in kernel's fs/proc/base.c file:
https://elixir.bootlin.com/linux/v6.2.8/source/fs/proc/base.c#L3238
I checked the difference between rest of declarations and it looks like
there is no more problems of such type affecting htop.
Diffstat (limited to 'linux/LinuxProcessList.c')
-rw-r--r-- | linux/LinuxProcessList.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index f8d56b70..b94c24a1 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -14,6 +14,7 @@ in the source distribution for its full text. #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <limits.h> #include <math.h> #include <stdbool.h> @@ -382,11 +383,15 @@ static inline ProcessState LinuxProcessList_getProcessState(char state) { } } -static bool LinuxProcessList_readStatFile(Process* process, openat_arg_t procFd, char* command, size_t commLen) { - LinuxProcess* lp = (LinuxProcess*) process; +static bool LinuxProcessList_readStatFile(LinuxProcess* lp, openat_arg_t procFd, bool scanMainThread, char* command, size_t commLen) { + Process* process = &lp->super; char buf[MAX_READ + 1]; - ssize_t r = xReadfileat(procFd, "stat", buf, sizeof(buf)); + char path[22] = "stat"; + if (scanMainThread) { + xSnprintf(path, sizeof(path), "task/%"PRIi32"/stat", (int32_t)process->pid); + } + ssize_t r = xReadfileat(procFd, path, buf, sizeof(buf)); if (r < 0) return false; @@ -607,9 +612,14 @@ static bool LinuxProcessList_updateUser(ProcessList* processList, Process* proce return true; } -static void LinuxProcessList_readIoFile(LinuxProcess* process, openat_arg_t procFd, unsigned long long realtimeMs) { +static void LinuxProcessList_readIoFile(LinuxProcess* process, openat_arg_t procFd, bool scanMainThread, unsigned long long realtimeMs) { + Process *proc = &process->super; + char path[20] = "io"; char buffer[1024]; - ssize_t r = xReadfileat(procFd, "io", buffer, sizeof(buffer)); + if (scanMainThread) { + xSnprintf(path, sizeof(path), "task/%"PRIi32"/io", (int32_t)proc->pid); + } + ssize_t r = xReadfileat(procFd, path, buffer, sizeof(buffer)); if (r < 0) { process->io_rate_read_bps = NAN; process->io_rate_write_bps = NAN; @@ -1531,8 +1541,9 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ continue; } + bool scanMainThread = !hideUserlandThreads && !Process_isKernelThread(proc) && !parent; if (ss->flags & PROCESS_FLAG_IO) - LinuxProcessList_readIoFile(lp, procFd, pl->realtimeMs); + LinuxProcessList_readIoFile(lp, procFd, scanMainThread, pl->realtimeMs); if (!LinuxProcessList_readStatmFile(lp, procFd)) goto errorReadingProcess; @@ -1580,7 +1591,7 @@ static bool LinuxProcessList_recurseProcTree(LinuxProcessList* this, openat_arg_ char statCommand[MAX_NAME + 1]; unsigned long long int lasttimes = (lp->utime + lp->stime); unsigned long int tty_nr = proc->tty_nr; - if (!LinuxProcessList_readStatFile(proc, procFd, statCommand, sizeof(statCommand))) + if (!LinuxProcessList_readStatFile(lp, procFd, scanMainThread, statCommand, sizeof(statCommand))) goto errorReadingProcess; if (lp->flags & PF_KTHREAD) { |