Permalink
Cannot retrieve contributors at this time
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?
mxq/ppidcache.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
120 lines (109 sloc)
3.09 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |