Skip to content

Commit

Permalink
linux: add ppid cache
Browse files Browse the repository at this point in the history
  • Loading branch information
HiGarfield committed Aug 30, 2024
1 parent 0a578f7 commit 1bbef60
Show file tree
Hide file tree
Showing 2 changed files with 1,257 additions and 48 deletions.
165 changes: 117 additions & 48 deletions src/process_iterator_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdlib.h>
#include "uthash.h"

struct ppid_info
{
pid_t pid;
pid_t ppid;
UT_hash_handle hh;
};

struct ppid_info *ppid_cache = NULL;

static int check_proc(void)
{
Expand All @@ -46,21 +57,40 @@ static int check_proc(void)
return 1;
}

int init_process_iterator(struct process_iterator *it, struct process_filter *filter)
static int is_numeric(const char *str)
{
if (!check_proc())
for (; *str != '\0' && isdigit(*str); str++)
;
return *str == '\0';
}

static void update_ppid_cache(struct process *p)
{
struct ppid_info *pi;
pid_t pid = p->pid;
HASH_FIND(hh, ppid_cache, &pid, sizeof(pid_t), pi);
if (pi != NULL)
{
fprintf(stderr, "procfs is not mounted!\nAborting\n");
exit(-2);
pi->ppid = p->ppid;
}
/* open a directory stream to /proc directory */
if ((it->dip = opendir("/proc")) == NULL)
else
{
perror("opendir");
return -1;
pi = (struct ppid_info *)malloc(sizeof(struct ppid_info));
pi->pid = p->pid;
pi->ppid = p->ppid;
HASH_ADD(hh, ppid_cache, pid, sizeof(pid_t), pi);
}
}

static void delete_from_ppid_cache(pid_t pid)
{
struct ppid_info *pi;
HASH_FIND(hh, ppid_cache, &pid, sizeof(pid_t), pi);
if (pi != NULL)
{
HASH_DEL(ppid_cache, pi);
free(pi);
}
it->filter = filter;
return 0;
}

static int read_process_info(pid_t pid, struct process *p)
Expand All @@ -74,48 +104,62 @@ static int read_process_info(pid_t pid, struct process *p)

p->pid = pid;

/* read command line */
sprintf(exefile, "/proc/%ld/cmdline", (long)p->pid);
if ((fd = fopen(exefile, "r")) != NULL)
/* read stat file */
sprintf(statfile, "/proc/%ld/stat", (long)p->pid);
if ((fd = fopen(statfile, "r")) != NULL)
{
if (fgets(p->command, sizeof(p->command), fd) == NULL)
if (fscanf(fd, "%*d (%*[^)]) %c %ld %*d %*d %*d %*d %*d %*d %*d %*d %*d %lf %lf",
&state, &ppid, &utime, &stime) == 4)
{
ret = -1;
p->ppid = (pid_t)ppid;
}
else
{
p->max_cmd_len = sizeof(p->command) - 1;
ret = -1;
}
if (ret == 0 && strchr("ZXx", state) != NULL)
{
ret = -1;
}
if (ret == 0)
{
if (sc_clk_tck < 0)
{
sc_clk_tck = (double)sysconf(_SC_CLK_TCK);
}
p->cputime = (utime + stime) * 1000.0 / sc_clk_tck;
}
fclose(fd);
if (ret != 0)
{
p->ppid = (pid_t)-1;
}
update_ppid_cache(p);
}
else
{
if (access(statfile, F_OK) != 0)
{
delete_from_ppid_cache(pid);
}
ret = -1;
}

if (ret != 0)
{
return ret;
}

/* read stat file */
sprintf(statfile, "/proc/%ld/stat", (long)p->pid);
if ((fd = fopen(statfile, "r")) != NULL)
/* read command line */
sprintf(exefile, "/proc/%ld/cmdline", (long)p->pid);
if ((fd = fopen(exefile, "r")) != NULL)
{
if (fscanf(fd, "%*d (%*[^)]) %c %ld %*d %*d %*d %*d %*d %*d %*d %*d %*d %lf %lf",
&state, &ppid, &utime, &stime) != 4 ||
strchr("ZXx", state) != NULL)
if (fgets(p->command, sizeof(p->command), fd) == NULL)
{
ret = -1;
}
else
{
p->ppid = (pid_t)ppid;
if (sc_clk_tck < 0)
{
sc_clk_tck = (double)sysconf(_SC_CLK_TCK);
}
p->cputime = (utime + stime) * 1000.0 / sc_clk_tck;
p->max_cmd_len = sizeof(p->command) - 1;
}
fclose(fd);
}
Expand All @@ -127,21 +171,53 @@ static int read_process_info(pid_t pid, struct process *p)
return ret;
}

pid_t getppid_of(pid_t pid)
static void clear_ppid_cache(void)
{
char statfile[32];
FILE *fd;
long ppid = -1;
if (pid <= 0)
return (pid_t)(-1);
sprintf(statfile, "/proc/%ld/stat", (long)pid);
if ((fd = fopen(statfile, "r")) != NULL)
struct ppid_info *current_item, *tmp;
HASH_ITER(hh, ppid_cache, current_item, tmp)
{
if (fscanf(fd, "%*d (%*[^)]) %*c %ld", &ppid) != 1)
ppid = -1;
fclose(fd);
HASH_DEL(ppid_cache, current_item);
free(current_item);
}
}

static void init_ppid_cache(void)
{
static int run = 1;
if (!run)
return;
atexit(&clear_ppid_cache);
run = 0;
}

int init_process_iterator(struct process_iterator *it, struct process_filter *filter)
{
init_ppid_cache();
if (!check_proc())
{
fprintf(stderr, "procfs is not mounted!\nAborting\n");
exit(-2);
}
/* open a directory stream to /proc directory */
if ((it->dip = opendir("/proc")) == NULL)
{
perror("opendir");
return -1;
}
return (pid_t)ppid;
it->filter = filter;
return 0;
}

pid_t getppid_of(pid_t pid)
{
struct ppid_info *pi;
struct process proc;
HASH_FIND(hh, ppid_cache, &pid, sizeof(pid_t), pi);
if (pi != NULL)
return pi->ppid;
if (read_process_info(pid, &proc) == 0)
return proc.ppid;
return (pid_t)-1;
}

static int get_start_time(pid_t pid, struct timespec *start_time)
Expand Down Expand Up @@ -186,13 +262,6 @@ int is_child_of(pid_t child_pid, pid_t parent_pid)
return 0;
}

static int is_numeric(const char *str)
{
for (; *str != '\0' && isdigit(*str); str++)
;
return *str == '\0';
}

int get_next_process(struct process_iterator *it, struct process *p)
{
struct dirent *dit = NULL;
Expand Down
Loading

0 comments on commit 1bbef60

Please sign in to comment.