Skip to content
Permalink
b798aee151
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
120 lines (109 sloc) 3.09 KB
#include <sys/types.h>
#include <errno.h>
#include "mx_util.h"
#include "ppidcache.h"
#include "mx_proc.h"
#include "mx_log.h"
struct entry {
pid_t pid;
pid_t parent;
};
struct ppidcache {
int count;
int alloc;
struct entry *entries;
};
struct ppidcache *ppidcache_new(void) {
struct ppidcache *ppidcache = mx_malloc_forever(sizeof(struct ppidcache));
ppidcache->count = 0;
ppidcache->alloc = 500;
ppidcache->entries = mx_malloc_forever(ppidcache->alloc*sizeof(struct entry));
return ppidcache;
}
void ppidcache_free(struct ppidcache *ppidcache) {
free(ppidcache->entries);
free(ppidcache);
}
static int _ppidcache_find(struct ppidcache *ppidcache, pid_t pid) {
int i;
for (i=0 ; i<ppidcache->count ; i++) {
if (ppidcache->entries[i].pid == pid)
return i;
}
return -1;
}
pid_t ppidcache_get_ppid(struct ppidcache *ppidcache, pid_t pid) {
int i = _ppidcache_find(ppidcache, pid);
if (i != -1)
return ppidcache->entries[i].parent;
if (ppidcache->count == ppidcache->alloc) {
ppidcache->alloc += 100;
struct entry *new = mx_malloc_forever(ppidcache->alloc * sizeof(struct entry));
memcpy(new, ppidcache->entries, ppidcache->count*sizeof(struct entry));
free(ppidcache->entries);
ppidcache->entries = new;
}
pid_t parent = mx_proc_get_parent(pid);
ppidcache->entries[ppidcache->count].pid = pid;
ppidcache->entries[ppidcache->count++].parent = parent;
return parent;
}
int ppidcache_is_descendant(struct ppidcache *ppidcache, pid_t ancestor, pid_t candidate) {
int fuse=100;
pid_t pid = candidate;
do {
pid = ppidcache_get_ppid(ppidcache, pid);
if (pid == 0 || pid == -1)
return 0;
if (pid == ancestor)
return 1;
} while (--fuse > 0);
return 0;
}
/*
* Load the cache with all pids from the system.
* Previous cached content, if any, is removed.
*/
void ppidcache_scan(struct ppidcache *ppidcache) {
_mx_cleanup_closedir_ DIR *dir = NULL;
pid_t pid;
struct dirent *dirent;
ppidcache->count = 0;
dir = opendir("/proc");
if (dir == NULL) {
mx_log_err("/proc: %m");
return;
}
while (1) {
errno = 0;
dirent = readdir(dir);
if (dirent == NULL) {
if (errno)
mx_log_err("/proc: %m");
return;
}
if (strspn(dirent->d_name, "0123456789") != strlen(dirent->d_name))
continue;
pid = atoi(dirent->d_name);
ppidcache_get_ppid(ppidcache, pid);
}
}
/*
* call cb(data, pid) for all cached(!) descendants.
* stop when no more descendants or when callback returns 0
*/
void ppidcache_do_descendants(
struct ppidcache *ppidcache,
pid_t pid,
int cb(void *data, pid_t pid),
void *data)
{
int next;
pid_t candidate;
for (next=0 ; next<ppidcache->count; next++) {
candidate = ppidcache->entries[next].pid;
if (ppidcache_is_descendant(ppidcache, pid, candidate))
if ((*cb)(data, candidate) == 0)
return;
}
}