From ffcaeb2f05dea9a6387e1d24bc9671c1aa879964 Mon Sep 17 00:00:00 2001 From: angelo Date: Wed, 6 Jun 2012 15:26:37 +0000 Subject: fixed compilation on freebsd --- .gitignore | 1 + src/Makefile | 2 +- src/cpulimit.c | 17 ----------------- tests/busy | Bin 8672 -> 5771 bytes tests/busy.c | 3 ++- 5 files changed, 4 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 1d390bb..04142b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o *~ src/cpulimit +busy diff --git a/src/Makefile b/src/Makefile index 33c632d..6deb69b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ CC?=gcc -CFLAGS?=-Wall -O2 +CFLAGS?=-Wall -O2 -D_GNU_SOURCE TARGETS=cpulimit LIBS=process.o procutils.o list.o diff --git a/src/cpulimit.c b/src/cpulimit.c index 300d320..6126c6b 100644 --- a/src/cpulimit.c +++ b/src/cpulimit.c @@ -99,23 +99,6 @@ int verbose = 0; //lazy mode (exits if there is no process) int lazy = 0; -static void *memrchr(const void *s, int c, size_t n) -{ - const unsigned char *start = (const unsigned char*)s; - const unsigned char *end = (const unsigned char*)s; - - end+=n-1; - - while(end>=start) { - if(*end==c) - return (void *)end; - else - end--; - } - - return NULL; -} - //SIGINT and SIGTERM signal handler static void quit(int sig) { diff --git a/tests/busy b/tests/busy index 1a8a589..2b00d78 100755 Binary files a/tests/busy and b/tests/busy differ diff --git a/tests/busy.c b/tests/busy.c index bb2e2ed..4839033 100644 --- a/tests/busy.c +++ b/tests/busy.c @@ -26,4 +26,5 @@ int main(int argc, char **argv) { printf("Press ENTER to exit..."); getchar(); return 0; -} \ No newline at end of file +} + -- cgit v1.2.3 From 3c10d8dc5820fde90bd293d95d82f5e4302d1c7d Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Wed, 6 Jun 2012 18:08:02 +0100 Subject: merged freebsd patch (from jesse smith) --- src/process.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/process.c b/src/process.c index 398d9e9..4f7403b 100644 --- a/src/process.c +++ b/src/process.c @@ -36,6 +36,16 @@ #include #endif +#ifdef __FreeBSD__ +#include +#include +#include +#include +#include +#include +#include +#endif + #ifdef __linux__ int get_proc_info(struct process *p, pid_t pid) { /* static char statfile[20]; @@ -148,6 +158,26 @@ static int get_jiffies(struct process *proc) { struct process proc2; get_proc_info(&proc2, proc->pid); return proc2.last_jiffies; +#elif defined __FreeBSD__ + kvm_t *my_kernel = NULL; + struct kinfo_proc *process_data = NULL; + int processes; + int my_jiffies = -1; + my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open"); + if (! my_kernel) + { + printf("Error opening kernel vm. You should be running as root.\n"); + return -1; + } + + process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes); + if ( (process_data) && (processes >= 1) ) + my_jiffies = process_data->ki_runtime; + + kvm_close(my_kernel); + if (my_jiffies >= 0) + my_jiffies /= 1000; + return my_jiffies; #endif } -- cgit v1.2.3 From d72e395ac6107e89b92e1c931b4b84ca42f60c2b Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Thu, 7 Jun 2012 02:24:56 +0100 Subject: started process iterator for FreeBSD. still unstable. --- src/Makefile | 2 +- src/process.c | 2 +- src/procutils.c | 21 +++++++++++++++++++++ src/procutils.h | 2 +- tests/busy | Bin 5771 -> 5220 bytes tests/busy.c | 5 ++--- 6 files changed, 26 insertions(+), 6 deletions(-) mode change 100644 => 100755 src/Makefile mode change 100644 => 100755 tests/busy.c diff --git a/src/Makefile b/src/Makefile old mode 100644 new mode 100755 index 6deb69b..6e7a89e --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CC?=gcc CFLAGS?=-Wall -O2 -D_GNU_SOURCE TARGETS=cpulimit -LIBS=process.o procutils.o list.o +LIBS=process.o procutils.o list.o -lkvm all:: $(TARGETS) diff --git a/src/process.c b/src/process.c index 4f7403b..73c5883 100644 --- a/src/process.c +++ b/src/process.c @@ -170,7 +170,7 @@ static int get_jiffies(struct process *proc) { return -1; } - process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes); + process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, proc->pid, &processes); if ( (process_data) && (processes >= 1) ) my_jiffies = process_data->ki_runtime; diff --git a/src/procutils.c b/src/procutils.c index fb7aaae..7cf0e71 100644 --- a/src/procutils.c +++ b/src/procutils.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "procutils.h" @@ -37,6 +38,10 @@ #include #endif +#ifdef __FreeBSD__ +#include +#endif + /* PROCESS STATISTICS FUNCTIONS */ //deprecated @@ -190,6 +195,22 @@ int init_process_iterator(struct process_iterator *i) { i->procList = result; i->count = err == 0 ? length / sizeof *result : 0; i->c = 0; +#elif defined __FreeBSD__ + kvm_t *kd; + struct kinfo_proc *procs = NULL; + char errbuf[_POSIX2_LINE_MAX]; + int count; + /* Open the kvm interface, get a descriptor */ + if ((kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) { + /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ + fprintf(stderr, "kvm_open: ", errbuf); + } + /* Get the list of processes. */ + if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) { + kvm_close(kd); + /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ + fprintf(stderr, "kvm_getprocs: ", kvm_geterr(kd)); + } #endif i->current = (struct process*)calloc(1, sizeof(struct process)); diff --git a/src/procutils.h b/src/procutils.h index b5a91a3..c39a239 100644 --- a/src/procutils.h +++ b/src/procutils.h @@ -62,7 +62,7 @@ struct process_iterator { struct kinfo_proc *procList; int count; int c; -#elif defined __hpux +#elif defined __FreeBSD__ int count; #endif struct process *current; diff --git a/tests/busy b/tests/busy index 2b00d78..c3a9aab 100755 Binary files a/tests/busy and b/tests/busy differ diff --git a/tests/busy.c b/tests/busy.c old mode 100644 new mode 100755 index 4839033..b3afb7c --- a/tests/busy.c +++ b/tests/busy.c @@ -13,7 +13,7 @@ int main(int argc, char **argv) { int i = 0; int num_threads = 1; if (argc == 2) num_threads = atoi(argv[1]); - for (i=0; i Date: Thu, 7 Jun 2012 11:23:14 +0100 Subject: removed process_exists(), code compiled on Linux and FreeBSD with same Makefile using gmake --- src/Makefile | 8 +++++++- src/process.c | 2 ++ src/procutils.c | 29 +++++++---------------------- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/Makefile b/src/Makefile index 6e7a89e..bacec4b 100755 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,13 @@ CC?=gcc CFLAGS?=-Wall -O2 -D_GNU_SOURCE TARGETS=cpulimit -LIBS=process.o procutils.o list.o -lkvm +LIBS=process.o procutils.o list.o + +UNAME := $(shell uname) + +ifeq ($(UNAME), FreeBSD) +LIBS+=-lkvm +endif all:: $(TARGETS) diff --git a/src/process.c b/src/process.c index 73c5883..53226a7 100644 --- a/src/process.c +++ b/src/process.c @@ -134,6 +134,8 @@ static int get_starttime(pid_t pid) struct process proc; get_proc_info(&proc, pid); return proc.starttime; +#elif defined __FreeBSD__ + return -1; #endif } diff --git a/src/procutils.c b/src/procutils.c index 7cf0e71..19b7054 100644 --- a/src/procutils.c +++ b/src/procutils.c @@ -68,6 +68,8 @@ static pid_t getppid_of(pid_t pid) struct process p; get_proc_info(&p, pid); return p.ppid; +#elif defined __FreeBSD__ + #endif } @@ -88,20 +90,6 @@ static int is_kernel_thread(pid_t pid) } #endif -//deprecated -// returns 1 if pid is an existing pid, 0 otherwise -static int process_exists(pid_t pid) { -#ifdef __linux__ - static char procdir[20]; - struct stat procstat; - sprintf(procdir, "/proc/%d", pid); - return stat(procdir, &procstat)==0; -#elif defined __APPLE__ - struct process p; - return get_proc_info(&p, pid)==0; -#endif -} - /* PID HASH FUNCTIONS */ static int hash_process(struct process_family *f, struct process *p) @@ -203,13 +191,13 @@ int init_process_iterator(struct process_iterator *i) { /* Open the kvm interface, get a descriptor */ if ((kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) { /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: ", errbuf); + fprintf(stderr, "kvm_open: %s", errbuf); } /* Get the list of processes. */ if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) { kvm_close(kd); /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ - fprintf(stderr, "kvm_getprocs: ", kvm_geterr(kd)); + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); } #endif @@ -409,14 +397,11 @@ void cleanup_process_family(struct process_family *f) // look for a process by pid // search_pid : pid of the wanted process -// return: pid of the found process, if it is found -// 0, if it's not found -// negative pid, if it is found but it's not possible to control it +// return: pid of the found process, if successful +// negative pid, if the process does not exist or if the signal fails int look_for_process_by_pid(pid_t pid) { - if (process_exists(pid)) - return (kill(pid,0)==0) ? pid : -pid; - return 0; + return (kill(pid,0)==0) ? pid : -pid; } // look for a process with a given name -- cgit v1.2.3 From 10c2915dd464de44047f182ecae9c8b34e24e772 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Thu, 7 Jun 2012 16:42:46 +0100 Subject: new cross-platform code to list processes. works on linux and freebsd --- src/Makefile | 5 +- src/process_iterator.c | 121 ++++++++++++++++++++++++++++++++++++++++++ src/process_iterator.h | 72 +++++++++++++++++++++++++ src/procutils.c | 2 +- tests/Makefile | 11 +++- tests/busy | Bin 5220 -> 5484 bytes tests/process_iterator_test | Bin 0 -> 6895 bytes tests/process_iterator_test.c | 18 +++++++ 8 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 src/process_iterator.c create mode 100644 src/process_iterator.h create mode 100755 tests/process_iterator_test create mode 100644 tests/process_iterator_test.c diff --git a/src/Makefile b/src/Makefile index bacec4b..57be683 100755 --- a/src/Makefile +++ b/src/Makefile @@ -9,11 +9,14 @@ ifeq ($(UNAME), FreeBSD) LIBS+=-lkvm endif -all:: $(TARGETS) +all:: $(TARGETS) process_iterator.o cpulimit: cpulimit.c $(LIBS) $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) +process_iterator.o: process_iterator.c process_iterator.h + $(CC) -c process_iterator.c $(CFLAGS) + process.o: process.c process.h $(CC) -c process.c $(CFLAGS) diff --git a/src/process_iterator.c b/src/process_iterator.c new file mode 100644 index 0000000..fd35952 --- /dev/null +++ b/src/process_iterator.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include "process_iterator.h" + +//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 + +#ifdef __linux__ + +int init_process_iterator(struct process_iterator *it) { + //open a directory stream to /proc directory + if ((it->dip = opendir("/proc")) == NULL) { + perror("opendir"); + return -1; + } + return 0; +} + +int read_next_process(struct process_iterator *it, struct process *p) { + char statfile[20]; + char buffer[1024]; + //read in from /proc and seek for process dirs + while ((it->dit = readdir(it->dip)) != NULL) { + if(strtok(it->dit->d_name, "0123456789") != NULL) + continue; + p->pid = atoi(it->dit->d_name); + //read stat file + sprintf(statfile, "/proc/%d/stat", p->pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) return -1; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) token = strtok(NULL, " "); + p->ppid = atoi(token); + for (i=0; i<10; i++) + token = strtok(NULL, " "); + p->last_jiffies = atoi(token); + token = strtok(NULL, " "); + p->last_jiffies += atoi(token); + for (i=0; i<7; i++) + token = strtok(NULL, " "); + p->starttime = atoi(token); + break; + //read command line + char exefile[20]; + sprintf(exefile,"/proc/%d/cmdline", p->pid); + fd = fopen(statfile, "r"); + char buffer[1024]; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + sscanf(buffer, "%s", (char*)&p->command); + } + if (it->dit == NULL) + { + //end of processes + closedir(it->dip); + it->dip = NULL; + return -1; + } + return 0; +} + +int close_process_iterator(struct process_iterator *it) { + if (it->dip != 0 && closedir(it->dip) == -1) { + perror("closedir"); + return 1; + } + return 0; +} + +#elif defined __APPLE__ + +#elif defined __FreeBSD__ + +#include +#include + +int init_process_iterator(struct process_iterator *it) { + char errbuf[_POSIX2_LINE_MAX]; + /* Open the kvm interface, get a descriptor */ + if ((it->kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) { + /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ + fprintf(stderr, "kvm_open: %s", errbuf); + return -1; + } + /* Get the list of processes. */ + if ((it->procs = kvm_getprocs(it->kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { + kvm_close(it->kd); + /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(it->kd)); + return -1; + } + kvm_close(it->kd); + it->i = 0; + return 0; +} + +int read_next_process(struct process_iterator *it, struct process *p) { + if (it->i == it->count) return -1; + p->pid = it->procs[it->i].ki_pid; + p->ppid = it->procs[it->i].ki_ppid; + p->last_jiffies = it->procs[it->i].ki_runtime / 1000; + it->i++; + return 0; +} + +int close_process_iterator(struct process_iterator *it) { + return 0; +} + +#endif diff --git a/src/process_iterator.h b/src/process_iterator.h new file mode 100644 index 0000000..fc559d3 --- /dev/null +++ b/src/process_iterator.h @@ -0,0 +1,72 @@ +/** + * + * cpulimit - a cpu limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PROCESS_ITERATOR_H + +#define __PROCESS_ITERATOR_H + +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#endif + +// process descriptor +struct process { + //pid of the process + pid_t pid; + //pid of the process + pid_t ppid; + //start time + int starttime; + //total number of jiffies used by the process at time last_sample + int last_jiffies; + //actual cpu usage estimation (value in range 0-1) + double cpu_usage; + //1 if the process is zombie + int is_zombie; + //absolute path of the executable file + char command[PATH_MAX+1]; +}; + +struct process_iterator { +#ifdef __linux__ + DIR *dip; + struct dirent *dit; +#elif defined __APPLE__ + struct kinfo_proc *procList; +#elif defined __FreeBSD__ + kvm_t *kd; + struct kinfo_proc *procs; + int count; + int i; +#endif +}; + +int init_process_iterator(struct process_iterator *i); + +int read_next_process(struct process_iterator *i, struct process *p); + +int close_process_iterator(struct process_iterator *i); + +#endif diff --git a/src/procutils.c b/src/procutils.c index 19b7054..7367196 100644 --- a/src/procutils.c +++ b/src/procutils.c @@ -69,7 +69,7 @@ static pid_t getppid_of(pid_t pid) get_proc_info(&p, pid); return p.ppid; #elif defined __FreeBSD__ - + #endif } diff --git a/tests/Makefile b/tests/Makefile index 11f7e2a..7f1c8b4 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,13 +1,22 @@ CC?=gcc CFLAGS?=-Wall -O2 -TARGETS=busy +TARGETS=busy process_iterator_test LIBS?=-lpthread +UNAME := $(shell uname) + +ifeq ($(UNAME), FreeBSD) +LIBS+=-lkvm +endif + all:: $(TARGETS) busy: busy.c $(LIBS) $(CC) -o busy busy.c $(LIBS) $(CFLAGS) +process_iterator_test: process_iterator_test.c $(LIBS) + $(CC) -I../src -o process_iterator_test process_iterator_test.c ../src/process_iterator.o $(LIBS) $(CFLAGS) + clean: rm -f *~ *.o $(TARGETS) diff --git a/tests/busy b/tests/busy index c3a9aab..45aa93b 100755 Binary files a/tests/busy and b/tests/busy differ diff --git a/tests/process_iterator_test b/tests/process_iterator_test new file mode 100755 index 0000000..979cf89 Binary files /dev/null and b/tests/process_iterator_test differ diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c new file mode 100644 index 0000000..080195a --- /dev/null +++ b/tests/process_iterator_test.c @@ -0,0 +1,18 @@ +#include +#include + +int main() +{ + struct process_iterator it; + struct process process; + init_process_iterator(&it); + while (read_next_process(&it, &process) != -1) + { + printf("Read process %d\n", process.pid); + printf("Parent %d\n", process.ppid); +// printf("Starttime %d\n", process.starttime); + printf("Jiffies %d\n", process.last_jiffies); + } + close_process_iterator(&it); + return 0; +} -- cgit v1.2.3 From fe6c77c340d7c83af7aea47d87f84d562c3da07a Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Fri, 8 Jun 2012 12:24:27 +0200 Subject: freebsd iterator works for non-privileged user --- src/process_iterator.c | 4 +++- tests/process_iterator_test | Bin 6895 -> 0 bytes 2 files changed, 3 insertions(+), 1 deletion(-) delete mode 100755 tests/process_iterator_test diff --git a/src/process_iterator.c b/src/process_iterator.c index fd35952..f0cee92 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -84,11 +84,13 @@ int close_process_iterator(struct process_iterator *it) { #include #include +#include +#include int init_process_iterator(struct process_iterator *it) { char errbuf[_POSIX2_LINE_MAX]; /* Open the kvm interface, get a descriptor */ - if ((it->kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) { + if ((it->kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ fprintf(stderr, "kvm_open: %s", errbuf); return -1; diff --git a/tests/process_iterator_test b/tests/process_iterator_test deleted file mode 100755 index 979cf89..0000000 Binary files a/tests/process_iterator_test and /dev/null differ -- cgit v1.2.3 From b774ed89bfeaf96905aaa85946771082302fc848 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Fri, 8 Jun 2012 12:25:36 +0200 Subject: executables deleted and ignored. some permission changes --- .gitignore | 1 + src/Makefile | 0 tests/busy | Bin 5484 -> 0 bytes tests/busy.c | 0 4 files changed, 1 insertion(+) mode change 100755 => 100644 src/Makefile delete mode 100755 tests/busy mode change 100755 => 100644 tests/busy.c diff --git a/.gitignore b/.gitignore index 04142b7..326c414 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *~ src/cpulimit busy +test/process_iterator_test diff --git a/src/Makefile b/src/Makefile old mode 100755 new mode 100644 diff --git a/tests/busy b/tests/busy deleted file mode 100755 index 45aa93b..0000000 Binary files a/tests/busy and /dev/null differ diff --git a/tests/busy.c b/tests/busy.c old mode 100755 new mode 100644 -- cgit v1.2.3 From 5544c90d488caf7d19ee3d6c828cf0490e60a3a5 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Fri, 15 Jun 2012 03:18:03 +0100 Subject: added filter to process_iterator. process_group and everything else broken --- src/Makefile | 17 +-- src/process_group.c | 72 +++++++++++++ src/process_group.h | 47 +++++++++ src/process_iterator.c | 234 +++++++++++++++++++++++++++++++++--------- src/process_iterator.h | 38 +++++-- tests/Makefile | 2 +- tests/process_iterator_test | Bin 0 -> 24672 bytes tests/process_iterator_test.c | 12 ++- 8 files changed, 353 insertions(+), 69 deletions(-) create mode 100644 src/process_group.c create mode 100644 src/process_group.h create mode 100755 tests/process_iterator_test diff --git a/src/Makefile b/src/Makefile index 57be683..f7a71ed 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CC?=gcc -CFLAGS?=-Wall -O2 -D_GNU_SOURCE +CFLAGS?=-Wall -g -D_GNU_SOURCE TARGETS=cpulimit -LIBS=process.o procutils.o list.o +LIBS=procutils.o list.o process_iterator.o UNAME := $(shell uname) @@ -17,15 +17,18 @@ cpulimit: cpulimit.c $(LIBS) process_iterator.o: process_iterator.c process_iterator.h $(CC) -c process_iterator.c $(CFLAGS) -process.o: process.c process.h - $(CC) -c process.c $(CFLAGS) +list.o: list.c list.h + $(CC) -c list.c $(CFLAGS) + +process_group.o: process_group.c process_group.h process_iterator.o list.o + $(CC) -c process_group.c $(CFLAGS) + +#process.o: process.c process.h +# $(CC) -c process.c $(CFLAGS) procutils.o: procutils.c procutils.h $(CC) -c procutils.c $(CFLAGS) -list.o: list.c list.h - $(CC) -c list.c $(CFLAGS) - clean: rm -f *~ *.o $(TARGETS) diff --git a/src/process_group.c b/src/process_group.c new file mode 100644 index 0000000..b8b1155 --- /dev/null +++ b/src/process_group.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include "process_group.h" +#include "list.h" + +int init_process_monitor(struct process_monitor *monitor, int target_pid, int ignore_children) +{ + //hashtable initialization + memset(&monitor->proctable, 0, sizeof(monitor->proctable)); + monitor->target_pid = target_pid; + monitor->ignore_children = ignore_children; + return 0; +} + +struct list* get_process_list(struct process_monitor *monitor) +{ + struct process_iterator it; + struct process process; + init_process_iterator(&it); + while (read_next_process(&it, &process) != -1) + { + if (monitor->ignore_children && process.pid != monitor->target_pid) continue; + printf("Read process %d\n", process.pid); + printf("Parent %d\n", process.ppid); + printf("Starttime %d\n", process.starttime); + printf("CPU time %d\n", process.cputime); + + int hashkey = pid_hashfn(process.pid + process.starttime); + if (monitor->proctable[hashkey] == NULL) + { + + if (is_ancestor(pid, ppid)) + struct process *ancestor = NULL; + while((ancestor=seek_process(f, ppid))==NULL) { + ppid = getppid_of(ppid); + } + + + //empty bucket + monitor->proctable[hashkey] = malloc(sizeof(struct list)); + struct process *new_process = malloc(sizeof(struct process)); + memcpy(new_process, &process, sizeof(struct process)); + init_list(monitor->proctable[hashkey], 4); + add_elem(monitor->proctable[hashkey], new_process); + } + else + { + + } + } + close_process_iterator(&it); + + return NULL; +} + +int close_process_monitor(struct process_monitor *monitor) +{ + int i; + int size = sizeof(monitor->proctable) / sizeof(struct process*); + for (i=0; iproctable[i] != NULL) { + //free() history for each process + destroy_list(monitor->proctable[i]); + free(monitor->proctable[i]); + monitor->proctable[i] = NULL; + } + } + monitor->target_pid = 0; + return 0; +} \ No newline at end of file diff --git a/src/process_group.h b/src/process_group.h new file mode 100644 index 0000000..eb4c5d8 --- /dev/null +++ b/src/process_group.h @@ -0,0 +1,47 @@ +/** + * + * cpulimit - a cpu limiter for Linux + * + * Copyright (C) 2005-2012, by: Angelo Marletta + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PROCESS_MONITOR_H + +#define __PROCESS_MONITOR_H + +#include "process_iterator.h" + +#include "list.h" + +#define PIDHASH_SZ 1024 +#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) + +struct process_monitor +{ + //hashtable with all the processes (array of struct list of struct process) + struct list *proctable[PIDHASH_SZ]; + pid_t target_pid; + int ignore_children; +}; + +int init_process_monitor(struct process_monitor *monitor, int target_pid, int ignore_children); + +struct list* get_process_list(struct process_monitor *monitor); + +int close_process_monitor(struct process_monitor *monitor); + +#endif \ No newline at end of file diff --git a/src/process_iterator.c b/src/process_iterator.c index f0cee92..bacf914 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -5,62 +5,106 @@ #include "process_iterator.h" -//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 +//See this link to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 #ifdef __linux__ -int init_process_iterator(struct process_iterator *it) { +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) +{ //open a directory stream to /proc directory - if ((it->dip = opendir("/proc")) == NULL) { + if ((it->dip = opendir("/proc")) == NULL) + { perror("opendir"); return -1; } + it->filter = filter; return 0; } -int read_next_process(struct process_iterator *it, struct process *p) { +static int read_process_info(pid_t pid, struct process *p) +{ + static char buffer[1024]; + static char statfile[32]; + static char exefile[1024]; + p->pid = pid; + //read stat file + sprintf(statfile, "/proc/%d/stat", p->pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) return -1; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) token = strtok(NULL, " "); + p->ppid = atoi(token); + for (i=0; i<10; i++) + token = strtok(NULL, " "); + p->cputime = atoi(token) * HZ; + token = strtok(NULL, " "); + p->cputime += atoi(token) * HZ; + for (i=0; i<7; i++) + token = strtok(NULL, " "); + p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); + //read command line + sprintf(exefile,"/proc/%d/cmdline", p->pid); + fd = fopen(statfile, "r"); + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + sscanf(buffer, "%s", (char*)&p->command); + return 0; +} + +static pid_t getppid_of(pid_t pid) +{ char statfile[20]; char buffer[1024]; + sprintf(statfile, "/proc/%d/stat", pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) return -1; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) token = strtok(NULL, " "); + return atoi(token); +} + +static int is_child_of(pid_t child_pid, pid_t parent_pid) +{ + int ppid = child_pid; + while(ppid > 1 && ppid != parent_pid) { + ppid = getppid_of(ppid); + } + return ppid == parent_pid; +} + +int read_next_process(struct process_iterator *it, struct process *p) +{ + if (it->filter->pid > 0 && !it->filter->include_children) + { + read_process_info(it->filter->pid, p); + return -1; + } + struct dirent *dit; //read in from /proc and seek for process dirs - while ((it->dit = readdir(it->dip)) != NULL) { - if(strtok(it->dit->d_name, "0123456789") != NULL) + while ((dit = readdir(it->dip)) != NULL) { + if(strtok(dit->d_name, "0123456789") != NULL) continue; - p->pid = atoi(it->dit->d_name); - //read stat file - sprintf(statfile, "/proc/%d/stat", p->pid); - FILE *fd = fopen(statfile, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd)==NULL) { - fclose(fd); - return -1; - } - fclose(fd); - char *token = strtok(buffer, " "); - int i; - for (i=0; i<3; i++) token = strtok(NULL, " "); - p->ppid = atoi(token); - for (i=0; i<10; i++) - token = strtok(NULL, " "); - p->last_jiffies = atoi(token); - token = strtok(NULL, " "); - p->last_jiffies += atoi(token); - for (i=0; i<7; i++) - token = strtok(NULL, " "); - p->starttime = atoi(token); + p->pid = atoi(dit->d_name); + if (it->filter->pid > 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue; + read_process_info(p->pid, p); break; - //read command line - char exefile[20]; - sprintf(exefile,"/proc/%d/cmdline", p->pid); - fd = fopen(statfile, "r"); - char buffer[1024]; - if (fgets(buffer, sizeof(buffer), fd)==NULL) { - fclose(fd); - return -1; - } - fclose(fd); - sscanf(buffer, "%s", (char*)&p->command); } - if (it->dit == NULL) + if (dit == NULL) { //end of processes closedir(it->dip); @@ -75,11 +119,10 @@ int close_process_iterator(struct process_iterator *it) { perror("closedir"); return 1; } + it->dip = NULL; return 0; } -#elif defined __APPLE__ - #elif defined __FreeBSD__ #include @@ -87,23 +130,30 @@ int close_process_iterator(struct process_iterator *it) { #include #include -int init_process_iterator(struct process_iterator *it) { +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + kvm_t *kd; char errbuf[_POSIX2_LINE_MAX]; + it->i = 0; /* Open the kvm interface, get a descriptor */ - if ((it->kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ fprintf(stderr, "kvm_open: %s", errbuf); return -1; } /* Get the list of processes. */ - if ((it->procs = kvm_getprocs(it->kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { - kvm_close(it->kd); + if ((it->procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { + kvm_close(kd); /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(it->kd)); + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); return -1; } - kvm_close(it->kd); - it->i = 0; + kvm_close(kd); + static int request[2] = { CTL_KERN, KERN_BOOTTIME }; + struct timeval result; + size_t result_len = sizeof result; + if (sysctl (request, 2, &result, &result_len, NULL, 0) < 0) return -1; + it->boot_time = result.tv_sec; + it->filter = filter; return 0; } @@ -111,13 +161,97 @@ int read_next_process(struct process_iterator *it, struct process *p) { if (it->i == it->count) return -1; p->pid = it->procs[it->i].ki_pid; p->ppid = it->procs[it->i].ki_ppid; - p->last_jiffies = it->procs[it->i].ki_runtime / 1000; + p->cputime = it->procs[it->i].ki_runtime / 1000; + p->starttime = it->procs[it->i].ki_start.tv_sec - it->boot_time; it->i++; + if (it->i == it->count) return -1; + return 0; +} + +int close_process_iterator(struct process_iterator *it) { + return 0; +} + +#elif defined __APPLE__ + +int init_process_iterator(struct process_iterator *it) { return 0; } +int read_next_process(struct process_iterator *it, struct process *p) { + return -1; +} + int close_process_iterator(struct process_iterator *it) { return 0; } + // int err; + // struct kinfo_proc *result = NULL; + // size_t length; + // int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + + // /* We start by calling sysctl with result == NULL and length == 0. + // That will succeed, and set length to the appropriate length. + // We then allocate a buffer of that size and call sysctl again + // with that buffer. + // */ + // length = 0; + // err = sysctl(mib, 4, NULL, &length, NULL, 0); + // if (err == -1) { + // err = errno; + // } + // if (err == 0) { + // result = malloc(length); + // err = sysctl(mib, 4, result, &length, NULL, 0); + // if (err == -1) + // err = errno; + // if (err == ENOMEM) { + // free(result); /* clean up */ + // result = NULL; + // } + // } + + // i->procList = result; + // i->count = err == 0 ? length / sizeof *result : 0; + // i->c = 0; + +// int get_proc_info(struct process *p, pid_t pid) { +// int err; +// struct kinfo_proc *result = NULL; +// size_t length; +// int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + +// /* We start by calling sysctl with result == NULL and length == 0. +// That will succeed, and set length to the appropriate length. +// We then allocate a buffer of that size and call sysctl again +// with that buffer. +// */ +// length = 0; +// err = sysctl(mib, 4, NULL, &length, NULL, 0); +// if (err == -1) { +// err = errno; +// } +// if (err == 0) { +// result = malloc(length); +// err = sysctl(mib, 4, result, &length, NULL, 0); +// if (err == -1) +// err = errno; +// if (err == ENOMEM) { +// free(result); /* clean up */ +// result = NULL; +// } +// } + +// p->pid = result->kp_proc.p_pid; +// p->ppid = result->kp_eproc.e_ppid; +// p->starttime = result->kp_proc.p_starttime.tv_sec; +// p->last_jiffies = result->kp_proc.p_cpticks; +// //p_pctcpu + +// return 0; +// } + +#elif defined __APPLE__ + #endif diff --git a/src/process_iterator.h b/src/process_iterator.h index fc559d3..23af7ed 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -27,6 +27,24 @@ #include #include +//USER_HZ detection, from openssl code +#ifndef HZ +# if defined(_SC_CLK_TCK) \ + && (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000) +# define HZ ((double)sysconf(_SC_CLK_TCK)) +# else +# ifndef CLK_TCK +# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */ +# define HZ 100.0 +# else /* _BSD_CLK_TCK_ */ +# define HZ ((double)_BSD_CLK_TCK_) +# endif +# else /* CLK_TCK */ +# define HZ ((double)CLK_TCK) +# endif +# endif +#endif + #ifdef __FreeBSD__ #include #endif @@ -39,8 +57,8 @@ struct process { pid_t ppid; //start time int starttime; - //total number of jiffies used by the process at time last_sample - int last_jiffies; + //cputime used by the process expressed in milliseconds + int cputime; //actual cpu usage estimation (value in range 0-1) double cpu_usage; //1 if the process is zombie @@ -49,21 +67,27 @@ struct process { char command[PATH_MAX+1]; }; +struct process_filter { + int pid; + int include_children; + char program_name[PATH_MAX+1]; +}; + struct process_iterator { #ifdef __linux__ DIR *dip; - struct dirent *dit; -#elif defined __APPLE__ - struct kinfo_proc *procList; #elif defined __FreeBSD__ - kvm_t *kd; + int boot_time; struct kinfo_proc *procs; int count; int i; +#elif defined __APPLE__ + struct kinfo_proc *procList; #endif + struct process_filter *filter; }; -int init_process_iterator(struct process_iterator *i); +int init_process_iterator(struct process_iterator *i, struct process_filter *filter); int read_next_process(struct process_iterator *i, struct process *p); diff --git a/tests/Makefile b/tests/Makefile index 7f1c8b4..11359e6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,5 @@ CC?=gcc -CFLAGS?=-Wall -O2 +CFLAGS?=-Wall -g TARGETS=busy process_iterator_test LIBS?=-lpthread diff --git a/tests/process_iterator_test b/tests/process_iterator_test new file mode 100755 index 0000000..f0204fd Binary files /dev/null and b/tests/process_iterator_test differ diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 080195a..b8aec52 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -5,13 +5,17 @@ int main() { struct process_iterator it; struct process process; - init_process_iterator(&it); - while (read_next_process(&it, &process) != -1) + struct process_filter filter; + filter.pid = 2981; + filter.include_children = 1; + init_process_iterator(&it, &filter); + while (read_next_process(&it, &process) == 0) { printf("Read process %d\n", process.pid); printf("Parent %d\n", process.ppid); -// printf("Starttime %d\n", process.starttime); - printf("Jiffies %d\n", process.last_jiffies); + printf("Starttime %d\n", process.starttime); + printf("CPU time %d\n", process.cputime); + printf("\n"); } close_process_iterator(&it); return 0; -- cgit v1.2.3 From fe9833bae838296ec2e17161fe666faba769b101 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Fri, 15 Jun 2012 03:25:33 +0100 Subject: fixed bug in cpu time calculation --- src/process_iterator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/process_iterator.c b/src/process_iterator.c index bacf914..a9e66ed 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -42,9 +42,9 @@ static int read_process_info(pid_t pid, struct process *p) p->ppid = atoi(token); for (i=0; i<10; i++) token = strtok(NULL, " "); - p->cputime = atoi(token) * HZ; + p->cputime = atoi(token) * 1000 / HZ; token = strtok(NULL, " "); - p->cputime += atoi(token) * HZ; + p->cputime += atoi(token) * 1000 / HZ; for (i=0; i<7; i++) token = strtok(NULL, " "); p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); -- cgit v1.2.3 From fe3e3c7e3be29d29b3b7efc22f4933c64e883776 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Sat, 16 Jun 2012 03:24:54 +0100 Subject: written two unit tests for process_iterator. tests pass --- .gitignore | 2 +- src/process_iterator.c | 40 ++++++++++++++++----- src/process_iterator.h | 2 +- tests/process_iterator_test | Bin 24672 -> 0 bytes tests/process_iterator_test.c | 80 ++++++++++++++++++++++++++++++++++++++---- 5 files changed, 107 insertions(+), 17 deletions(-) delete mode 100755 tests/process_iterator_test diff --git a/.gitignore b/.gitignore index 326c414..70e4875 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ *~ src/cpulimit busy -test/process_iterator_test +process_iterator_test diff --git a/src/process_iterator.c b/src/process_iterator.c index a9e66ed..eb34d62 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -2,13 +2,33 @@ #include #include #include - +#include #include "process_iterator.h" //See this link to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 #ifdef __linux__ +static int get_boot_time() +{ + int uptime; + FILE *fp = fopen ("/proc/uptime", "r"); + if (fp != NULL) + { + char buf[BUFSIZ]; + char *b = fgets(buf, BUFSIZ, fp); + if (b == buf) + { + char *end_ptr; + double upsecs = strtod(buf, &end_ptr); + uptime = (int)upsecs; + } + fclose (fp); + } + time_t now = time(NULL); + return now - uptime; +} + int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { //open a directory stream to /proc directory @@ -18,6 +38,7 @@ int init_process_iterator(struct process_iterator *it, struct process_filter *fi return -1; } it->filter = filter; + it->boot_time = get_boot_time(); return 0; } @@ -89,10 +110,17 @@ static int is_child_of(pid_t child_pid, pid_t parent_pid) int read_next_process(struct process_iterator *it, struct process *p) { + if (it->dip == NULL) + { + //end of processes + return -1; + } if (it->filter->pid > 0 && !it->filter->include_children) { read_process_info(it->filter->pid, p); - return -1; + p->starttime += it->boot_time; + it->dip = NULL; + return 0; } struct dirent *dit; //read in from /proc and seek for process dirs @@ -102,6 +130,7 @@ int read_next_process(struct process_iterator *it, struct process *p) p->pid = atoi(dit->d_name); if (it->filter->pid > 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue; read_process_info(p->pid, p); + p->starttime += it->boot_time; break; } if (dit == NULL) @@ -148,11 +177,6 @@ int init_process_iterator(struct process_iterator *it, struct process_filter *fi return -1; } kvm_close(kd); - static int request[2] = { CTL_KERN, KERN_BOOTTIME }; - struct timeval result; - size_t result_len = sizeof result; - if (sysctl (request, 2, &result, &result_len, NULL, 0) < 0) return -1; - it->boot_time = result.tv_sec; it->filter = filter; return 0; } @@ -162,7 +186,7 @@ int read_next_process(struct process_iterator *it, struct process *p) { p->pid = it->procs[it->i].ki_pid; p->ppid = it->procs[it->i].ki_ppid; p->cputime = it->procs[it->i].ki_runtime / 1000; - p->starttime = it->procs[it->i].ki_start.tv_sec - it->boot_time; + p->starttime = it->procs[it->i].ki_start.tv_sec; it->i++; if (it->i == it->count) return -1; return 0; diff --git a/src/process_iterator.h b/src/process_iterator.h index 23af7ed..711cf3b 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -76,8 +76,8 @@ struct process_filter { struct process_iterator { #ifdef __linux__ DIR *dip; -#elif defined __FreeBSD__ int boot_time; +#elif defined __FreeBSD__ struct kinfo_proc *procs; int count; int i; diff --git a/tests/process_iterator_test b/tests/process_iterator_test deleted file mode 100755 index f0204fd..0000000 Binary files a/tests/process_iterator_test and /dev/null differ diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index b8aec52..1822449 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -1,22 +1,88 @@ #include #include +#include +#include +#include +#include -int main() +int test_single_process() +{ + struct process_iterator it; + struct process process; + struct process_filter filter; + int count; + time_t now; + //don't iterate children + filter.pid = getpid(); + filter.include_children = 0; + count = 0; + now = time(NULL); + init_process_iterator(&it, &filter); + while (read_next_process(&it, &process) == 0) + { + assert(process.pid == getpid()); + assert(process.ppid == getppid()); + assert(process.cputime < 100); + assert(process.starttime == now || process.starttime == now - 1); + + count++; + } + assert(count == 1); + close_process_iterator(&it); + //iterate children + filter.pid = getpid(); + filter.include_children = 1; + count = 0; + now = time(NULL); + init_process_iterator(&it, &filter); + while (read_next_process(&it, &process) == 0) + { + assert(process.pid == getpid()); + assert(process.ppid == getppid()); + assert(process.cputime < 100); + assert(process.starttime == now || process.starttime == now - 1); + count++; + } + assert(count == 1); + close_process_iterator(&it); + return 0; +} + +int test_multiple_process() { struct process_iterator it; struct process process; struct process_filter filter; - filter.pid = 2981; + int child = fork(); + if (child == 0) + { + //child code + sleep(1); + return 0; + } + filter.pid = getpid(); filter.include_children = 1; init_process_iterator(&it, &filter); + int count = 0; + time_t now = time(NULL); while (read_next_process(&it, &process) == 0) { - printf("Read process %d\n", process.pid); - printf("Parent %d\n", process.ppid); - printf("Starttime %d\n", process.starttime); - printf("CPU time %d\n", process.cputime); - printf("\n"); + if (process.pid == getpid()) assert(process.ppid == getppid()); + else if (process.pid == child) assert(process.ppid == getpid()); + else assert(0); + assert(process.cputime < 100); + assert(process.starttime == now || process.starttime == now - 1); + count++; } + assert(count == 2); close_process_iterator(&it); return 0; } + +int main() +{ + printf("Current PID %d\n", getpid()); + test_single_process(); + test_multiple_process(); + return 0; +} \ No newline at end of file -- cgit v1.2.3 From 01a76753a060c27e26ac691c0d69f99b975038e5 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Tue, 19 Jun 2012 01:23:06 +0100 Subject: process_iterator working for linux and freebsd. tests pass --- src/Makefile | 10 +++---- src/process_iterator.c | 70 ++++++++++++++++++++++++++++++++++++------- src/process_iterator.h | 2 +- tests/Makefile | 2 +- tests/process_iterator_test.c | 38 ++++++++++++++++++----- 5 files changed, 98 insertions(+), 24 deletions(-) diff --git a/src/Makefile b/src/Makefile index f7a71ed..7e2bc94 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,10 +9,10 @@ ifeq ($(UNAME), FreeBSD) LIBS+=-lkvm endif -all:: $(TARGETS) process_iterator.o +all:: process_iterator.o -cpulimit: cpulimit.c $(LIBS) - $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) +#cpulimit: cpulimit.c $(LIBS) +# $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) process_iterator.o: process_iterator.c process_iterator.h $(CC) -c process_iterator.c $(CFLAGS) @@ -26,8 +26,8 @@ process_group.o: process_group.c process_group.h process_iterator.o list.o #process.o: process.c process.h # $(CC) -c process.c $(CFLAGS) -procutils.o: procutils.c procutils.h - $(CC) -c procutils.c $(CFLAGS) +#procutils.o: procutils.c procutils.h +# $(CC) -c procutils.c $(CFLAGS) clean: rm -f *~ *.o $(TARGETS) diff --git a/src/process_iterator.c b/src/process_iterator.c index eb34d62..ff13035 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -108,7 +108,7 @@ static int is_child_of(pid_t child_pid, pid_t parent_pid) return ppid == parent_pid; } -int read_next_process(struct process_iterator *it, struct process *p) +int get_next_process(struct process_iterator *it, struct process *p) { if (it->dip == NULL) { @@ -181,17 +181,67 @@ int init_process_iterator(struct process_iterator *it, struct process_filter *fi return 0; } -int read_next_process(struct process_iterator *it, struct process *p) { - if (it->i == it->count) return -1; - p->pid = it->procs[it->i].ki_pid; - p->ppid = it->procs[it->i].ki_ppid; - p->cputime = it->procs[it->i].ki_runtime / 1000; - p->starttime = it->procs[it->i].ki_start.tv_sec; - it->i++; - if (it->i == it->count) return -1; +static void kproc2proc(struct kinfo_proc *kproc, struct process *proc) +{ + proc->pid = kproc->ki_pid; + proc->ppid = kproc->ki_ppid; + proc->cputime = kproc->ki_runtime / 1000; + proc->starttime = kproc->ki_start.tv_sec; +} + +static int get_single_process(pid_t pid, struct process *process) +{ + kvm_t *kd; + int count; + char errbuf[_POSIX2_LINE_MAX]; + /* Open the kvm interface, get a descriptor */ + if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ + fprintf(stderr, "kvm_open: %s", errbuf); + return -1; + } + struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); + kvm_close(kd); + if (count == 0 || kproc == NULL) + { + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); + return -1; + } + kproc2proc(kproc, process); return 0; } +int get_next_process(struct process_iterator *it, struct process *p) { + if (it->i == it->count) + { + return -1; + } + if (it->filter->pid > 0 && !it->filter->include_children) + { + get_single_process(it->filter->pid, p); + it->i = it->count = 1; + return 0; + } + while (it->i < it->count) + { + if (it->filter->pid > 0 && it->filter->include_children) + { + kproc2proc(&(it->procs[it->i]), p); + it->i++; + if (p->pid != it->filter->pid && p->ppid != it->filter->pid) + continue; + return 0; + } + else if (it->filter->pid == 0) + { + kproc2proc(&(it->procs[it->i]), p); + it->i++; + return 0; + } + } + return -1; +} + int close_process_iterator(struct process_iterator *it) { return 0; } @@ -202,7 +252,7 @@ int init_process_iterator(struct process_iterator *it) { return 0; } -int read_next_process(struct process_iterator *it, struct process *p) { +int get_next_process(struct process_iterator *it, struct process *p) { return -1; } diff --git a/src/process_iterator.h b/src/process_iterator.h index 711cf3b..1e118f4 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -89,7 +89,7 @@ struct process_iterator { int init_process_iterator(struct process_iterator *i, struct process_filter *filter); -int read_next_process(struct process_iterator *i, struct process *p); +int get_next_process(struct process_iterator *i, struct process *p); int close_process_iterator(struct process_iterator *i); diff --git a/tests/Makefile b/tests/Makefile index 11359e6..d187359 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -14,7 +14,7 @@ all:: $(TARGETS) busy: busy.c $(LIBS) $(CC) -o busy busy.c $(LIBS) $(CFLAGS) -process_iterator_test: process_iterator_test.c $(LIBS) +process_iterator_test: process_iterator_test.c $(LIBS) ../src/process_iterator.o $(CC) -I../src -o process_iterator_test process_iterator_test.c ../src/process_iterator.o $(LIBS) $(CFLAGS) clean: diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 1822449..ac5d542 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -18,24 +18,23 @@ int test_single_process() count = 0; now = time(NULL); init_process_iterator(&it, &filter); - while (read_next_process(&it, &process) == 0) + while (get_next_process(&it, &process) == 0) { assert(process.pid == getpid()); assert(process.ppid == getppid()); assert(process.cputime < 100); assert(process.starttime == now || process.starttime == now - 1); - count++; } assert(count == 1); close_process_iterator(&it); //iterate children filter.pid = getpid(); - filter.include_children = 1; + filter.include_children = 0; count = 0; now = time(NULL); init_process_iterator(&it, &filter); - while (read_next_process(&it, &process) == 0) + while (get_next_process(&it, &process) == 0) { assert(process.pid == getpid()); assert(process.ppid == getppid()); @@ -65,7 +64,7 @@ int test_multiple_process() init_process_iterator(&it, &filter); int count = 0; time_t now = time(NULL); - while (read_next_process(&it, &process) == 0) + while (get_next_process(&it, &process) == 0) { if (process.pid == getpid()) assert(process.ppid == getppid()); else if (process.pid == child) assert(process.ppid == getpid()); @@ -79,10 +78,35 @@ int test_multiple_process() return 0; } +int test_all_processes() +{ + struct process_iterator it; + struct process process; + struct process_filter filter; + filter.pid = 0; + init_process_iterator(&it, &filter); + int count = 0; + time_t now = time(NULL); + while (get_next_process(&it, &process) == 0) + { + if (process.pid == getpid()) + { + assert(process.ppid == getppid()); + assert(process.cputime < 100); + assert(process.starttime == now || process.starttime == now - 1); + } + count++; + } + assert(count >= 10); + close_process_iterator(&it); + return 0; +} + int main() { - printf("Current PID %d\n", getpid()); + printf("Pid %d\n", getpid()); test_single_process(); test_multiple_process(); + test_all_processes(); return 0; -} \ No newline at end of file +} -- cgit v1.2.3 From c08039365f62abe5f180c9c3c6c3f8fac6feb378 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Wed, 20 Jun 2012 02:48:05 +0100 Subject: added process_group and test. all tests pass --- src/Makefile | 5 +-- src/process_group.c | 76 ++++++++++++++++++++----------------------- src/process_group.h | 17 +++++----- src/process_iterator.c | 2 +- src/process_iterator.h | 2 +- tests/Makefile | 13 ++++---- tests/process_iterator_test.c | 26 ++++++++++----- 7 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7e2bc94..e6e819f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,8 @@ CC?=gcc CFLAGS?=-Wall -g -D_GNU_SOURCE TARGETS=cpulimit -LIBS=procutils.o list.o process_iterator.o +#LIBS=procutils.o list.o process_iterator.o +LIBS=list.o process_iterator.o process_group.o UNAME := $(shell uname) @@ -9,7 +10,7 @@ ifeq ($(UNAME), FreeBSD) LIBS+=-lkvm endif -all:: process_iterator.o +all:: $(LIBS) #cpulimit: cpulimit.c $(LIBS) # $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) diff --git a/src/process_group.c b/src/process_group.c index b8b1155..2afef71 100644 --- a/src/process_group.c +++ b/src/process_group.c @@ -2,71 +2,67 @@ #include #include #include + +#include "process_iterator.h" #include "process_group.h" #include "list.h" -int init_process_monitor(struct process_monitor *monitor, int target_pid, int ignore_children) +int init_process_group(struct process_group *pgroup, int target_pid, int include_children) { //hashtable initialization - memset(&monitor->proctable, 0, sizeof(monitor->proctable)); - monitor->target_pid = target_pid; - monitor->ignore_children = ignore_children; + memset(&pgroup->proctable, 0, sizeof(pgroup->proctable)); + pgroup->target_pid = target_pid; + pgroup->include_children = include_children; + pgroup->proclist = (struct list*)malloc(sizeof(struct list)); + return 0; +} + +int close_process_group(struct process_group *pgroup) +{ + int i; + int size = sizeof(pgroup->proctable) / sizeof(struct process*); + for (i=0; iproctable[i] != NULL) { + //free() history for each process + destroy_list(pgroup->proctable[i]); + free(pgroup->proctable[i]); + pgroup->proctable[i] = NULL; + } + } + free(pgroup->proclist); + pgroup->proclist = NULL; return 0; } -struct list* get_process_list(struct process_monitor *monitor) +void update_process_group(struct process_group *pgroup) { struct process_iterator it; struct process process; - init_process_iterator(&it); - while (read_next_process(&it, &process) != -1) + struct process_filter filter; + filter.pid = pgroup->target_pid; + filter.include_children = pgroup->include_children; + init_process_iterator(&it, &filter); + while (get_next_process(&it, &process) != -1) { - if (monitor->ignore_children && process.pid != monitor->target_pid) continue; printf("Read process %d\n", process.pid); printf("Parent %d\n", process.ppid); printf("Starttime %d\n", process.starttime); printf("CPU time %d\n", process.cputime); - int hashkey = pid_hashfn(process.pid + process.starttime); - if (monitor->proctable[hashkey] == NULL) + if (pgroup->proctable[hashkey] == NULL) { - - if (is_ancestor(pid, ppid)) - struct process *ancestor = NULL; - while((ancestor=seek_process(f, ppid))==NULL) { - ppid = getppid_of(ppid); - } - - //empty bucket - monitor->proctable[hashkey] = malloc(sizeof(struct list)); + pgroup->proctable[hashkey] = malloc(sizeof(struct list)); struct process *new_process = malloc(sizeof(struct process)); memcpy(new_process, &process, sizeof(struct process)); - init_list(monitor->proctable[hashkey], 4); - add_elem(monitor->proctable[hashkey], new_process); + init_list(pgroup->proctable[hashkey], 4); + add_elem(pgroup->proctable[hashkey], new_process); } else { - + //existing bucket + } } close_process_iterator(&it); - - return NULL; } - -int close_process_monitor(struct process_monitor *monitor) -{ - int i; - int size = sizeof(monitor->proctable) / sizeof(struct process*); - for (i=0; iproctable[i] != NULL) { - //free() history for each process - destroy_list(monitor->proctable[i]); - free(monitor->proctable[i]); - monitor->proctable[i] = NULL; - } - } - monitor->target_pid = 0; - return 0; -} \ No newline at end of file diff --git a/src/process_group.h b/src/process_group.h index eb4c5d8..27c3352 100644 --- a/src/process_group.h +++ b/src/process_group.h @@ -19,9 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __PROCESS_MONITOR_H +#ifndef __PROCESS_GROUP_H -#define __PROCESS_MONITOR_H +#define __PROCESS_GROUP_H #include "process_iterator.h" @@ -30,18 +30,19 @@ #define PIDHASH_SZ 1024 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) -struct process_monitor +struct process_group { //hashtable with all the processes (array of struct list of struct process) struct list *proctable[PIDHASH_SZ]; + struct list *proclist; pid_t target_pid; - int ignore_children; + int include_children; }; -int init_process_monitor(struct process_monitor *monitor, int target_pid, int ignore_children); +int init_process_group(struct process_group *pgroup, int target_pid, int include_children); -struct list* get_process_list(struct process_monitor *monitor); +void update_process_group(struct process_group *pgroup); -int close_process_monitor(struct process_monitor *monitor); +int close_process_group(struct process_group *pgroup); -#endif \ No newline at end of file +#endif diff --git a/src/process_iterator.c b/src/process_iterator.c index ff13035..e27ed4c 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -286,7 +286,7 @@ int close_process_iterator(struct process_iterator *it) { // } // } - // i->procList = result; + // i->proclist = result; // i->count = err == 0 ? length / sizeof *result : 0; // i->c = 0; diff --git a/src/process_iterator.h b/src/process_iterator.h index 1e118f4..1747644 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -82,7 +82,7 @@ struct process_iterator { int count; int i; #elif defined __APPLE__ - struct kinfo_proc *procList; + struct kinfo_proc *proclist; #endif struct process_filter *filter; }; diff --git a/tests/Makefile b/tests/Makefile index d187359..ffc80fa 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,8 +1,9 @@ CC?=gcc CFLAGS?=-Wall -g TARGETS=busy process_iterator_test -LIBS?=-lpthread - +SRC=../src +SYSLIBS?=-lpthread +LIBS=$(SRC)/list.o $(SRC)/process_iterator.o $(SRC)/process_group.o UNAME := $(shell uname) ifeq ($(UNAME), FreeBSD) @@ -11,11 +12,11 @@ endif all:: $(TARGETS) -busy: busy.c $(LIBS) - $(CC) -o busy busy.c $(LIBS) $(CFLAGS) +busy: busy.c $(SYSLIBS) + $(CC) -o busy busy.c $(SYSLIBS) $(CFLAGS) -process_iterator_test: process_iterator_test.c $(LIBS) ../src/process_iterator.o - $(CC) -I../src -o process_iterator_test process_iterator_test.c ../src/process_iterator.o $(LIBS) $(CFLAGS) +process_iterator_test: process_iterator_test.c $(LIBS) + $(CC) -I$(SRC) -o process_iterator_test process_iterator_test.c $(LIBS) $(SYSLIBS) $(CFLAGS) clean: rm -f *~ *.o $(TARGETS) diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index ac5d542..dcd4ebe 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -1,11 +1,14 @@ #include -#include +#include #include #include #include #include -int test_single_process() +#include +#include + +void test_single_process() { struct process_iterator it; struct process process; @@ -44,10 +47,9 @@ int test_single_process() } assert(count == 1); close_process_iterator(&it); - return 0; } -int test_multiple_process() +void test_multiple_process() { struct process_iterator it; struct process process; @@ -57,7 +59,7 @@ int test_multiple_process() { //child code sleep(1); - return 0; + exit(0); } filter.pid = getpid(); filter.include_children = 1; @@ -75,10 +77,9 @@ int test_multiple_process() } assert(count == 2); close_process_iterator(&it); - return 0; } -int test_all_processes() +void test_all_processes() { struct process_iterator it; struct process process; @@ -99,7 +100,15 @@ int test_all_processes() } assert(count >= 10); close_process_iterator(&it); - return 0; +} + +void test_process_list() +{ + struct process_group pgroup; + pid_t current_pid = getpid(); + assert(init_process_group(&pgroup, current_pid, 0) == 0); + update_process_group(&pgroup); + assert(close_process_group(&pgroup) == 0); } int main() @@ -108,5 +117,6 @@ int main() test_single_process(); test_multiple_process(); test_all_processes(); + test_process_list(); return 0; } -- cgit v1.2.3 From ce079fc58d6d30c3fe400a777934b4a4cce85761 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Thu, 21 Jun 2012 02:06:58 +0100 Subject: multiplatform refactoring. added more tests. works but there is a fd leak. --- src/list.c | 2 +- src/list.h | 2 +- src/process_group.c | 110 ++++++++++++-- src/process_group.h | 1 + src/process_iterator.c | 315 +---------------------------------------- src/process_iterator.h | 8 +- src/process_iterator_apple.c | 77 ++++++++++ src/process_iterator_freebsd.c | 92 ++++++++++++ src/process_iterator_linux.c | 142 +++++++++++++++++++ tests/process_iterator_test.c | 86 ++++++++--- 10 files changed, 492 insertions(+), 343 deletions(-) create mode 100644 src/process_iterator_apple.c create mode 100644 src/process_iterator_freebsd.c create mode 100644 src/process_iterator_linux.c diff --git a/src/list.c b/src/list.c index 49f84ce..6fe1e06 100644 --- a/src/list.c +++ b/src/list.c @@ -127,7 +127,7 @@ void *locate_elem(struct list *l,void *elem) { return(xlocate_elem(l,elem,0,0)); } -void flush_list(struct list *l) { +void clear_list(struct list *l) { struct list_node *tmp; while(l->first!=EMPTYLIST) { tmp=l->first; diff --git a/src/list.h b/src/list.h index 387f79c..478635f 100644 --- a/src/list.h +++ b/src/list.h @@ -133,7 +133,7 @@ void *locate_elem(struct list *l,void *elem); /* * Delete all the elements in the list */ -void flush_list(struct list *l); +void clear_list(struct list *l); /* * Delete every element in the list, and free the memory pointed by all the node data diff --git a/src/process_group.c b/src/process_group.c index 2afef71..043ee69 100644 --- a/src/process_group.c +++ b/src/process_group.c @@ -2,6 +2,9 @@ #include #include #include +#include + +#include #include "process_iterator.h" #include "process_group.h" @@ -14,6 +17,8 @@ int init_process_group(struct process_group *pgroup, int target_pid, int include pgroup->target_pid = target_pid; pgroup->include_children = include_children; pgroup->proclist = (struct list*)malloc(sizeof(struct list)); + init_list(pgroup->proclist, 4); + memset(&pgroup->last_update, 0, sizeof(pgroup->last_update)); return 0; } @@ -29,40 +34,127 @@ int close_process_group(struct process_group *pgroup) pgroup->proctable[i] = NULL; } } + clear_list(pgroup->proclist); free(pgroup->proclist); pgroup->proclist = NULL; return 0; } +void remove_terminated_processes(struct process_group *pgroup) +{ + //TODO +} + +//return t1-t2 in microseconds (no overflow checks, so better watch out!) +static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) +{ + return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec); +} + +//parameter in range 0-1 +#define ALFA 0.08 + +int process_monitor(struct process *proc) +{ + // int j = get_jiffies(proc); + // if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead) + // struct timeval now; + // gettimeofday(&now, NULL); + // if (proc->last_jiffies==-1) { + // //store current time + // proc->last_sample = now; + // //store current jiffies + // proc->last_jiffies = j; + // //it's the first sample, cannot figure out the cpu usage + // proc->cpu_usage = -1; + // return 0; + // } + // //time from previous sample (in ns) + // long dt = timediff(&now, &(proc->last_sample)); + // //how many jiffies in dt? + // double max_jiffies = dt * HZ / 1000000.0; + // double sample = (j - proc->last_jiffies) / max_jiffies; + // if (proc->cpu_usage == -1) { + // //initialization + // proc->cpu_usage = sample; + // } + // else { + // //usage adjustment + // proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample; + // } + // //store current time + // proc->last_sample = now; + // //store current jiffies + // proc->last_jiffies = j; + return 0; +} + void update_process_group(struct process_group *pgroup) { struct process_iterator it; - struct process process; + struct process tmp_process; struct process_filter filter; filter.pid = pgroup->target_pid; filter.include_children = pgroup->include_children; init_process_iterator(&it, &filter); - while (get_next_process(&it, &process) != -1) + clear_list(pgroup->proclist); + init_list(pgroup->proclist, 4); + struct timeval now; + gettimeofday(&now, NULL); + //time elapsed from previous sample (in ms) + long dt = timediff(&now, &pgroup->last_update) / 1000; + while (get_next_process(&it, &tmp_process) != -1) { - printf("Read process %d\n", process.pid); - printf("Parent %d\n", process.ppid); - printf("Starttime %d\n", process.starttime); - printf("CPU time %d\n", process.cputime); - int hashkey = pid_hashfn(process.pid + process.starttime); + // printf("Read process %d\n", tmp_process.pid); + // printf("Parent %d\n", tmp_process.ppid); + // printf("Starttime %d\n", tmp_process.starttime); + // printf("CPU time %d\n", tmp_process.cputime); + int hashkey = pid_hashfn(tmp_process.pid + tmp_process.starttime); if (pgroup->proctable[hashkey] == NULL) { //empty bucket pgroup->proctable[hashkey] = malloc(sizeof(struct list)); struct process *new_process = malloc(sizeof(struct process)); - memcpy(new_process, &process, sizeof(struct process)); + tmp_process.cpu_usage = -1; + memcpy(new_process, &tmp_process, sizeof(struct process)); init_list(pgroup->proctable[hashkey], 4); add_elem(pgroup->proctable[hashkey], new_process); + add_elem(pgroup->proclist, new_process); } else { //existing bucket - + struct process *p = (struct process*)locate_elem(pgroup->proctable[hashkey], &tmp_process); + if (p == NULL) + { + //process is new. add it + struct process *new_process = malloc(sizeof(struct process)); + tmp_process.cpu_usage = -1; + memcpy(new_process, &tmp_process, sizeof(struct process)); + add_elem(pgroup->proctable[hashkey], new_process); + add_elem(pgroup->proclist, new_process); + } + else + { + assert(tmp_process.pid == p->pid); + assert(tmp_process.ppid == p->ppid); + assert(tmp_process.starttime == p->starttime); + //process exists. update CPU usage + double sample = (tmp_process.cputime - p->cputime) / dt; + if (p->cpu_usage == -1) { + //initialization + p->cpu_usage = sample; + } + else { + //usage adjustment + p->cpu_usage = (1-ALFA) * p->cpu_usage + ALFA * sample; + } + p->cpu_usage = (1-ALFA) * p->cpu_usage + ALFA * sample; + p->cputime = tmp_process.cputime; + add_elem(pgroup->proclist, p); + } } } close_process_iterator(&it); + pgroup->last_update = now; } diff --git a/src/process_group.h b/src/process_group.h index 27c3352..f26d2cb 100644 --- a/src/process_group.h +++ b/src/process_group.h @@ -37,6 +37,7 @@ struct process_group struct list *proclist; pid_t target_pid; int include_children; + struct timeval last_update; }; int init_process_group(struct process_group *pgroup, int target_pid, int include_children); diff --git a/src/process_iterator.c b/src/process_iterator.c index e27ed4c..0e31c81 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -9,323 +9,18 @@ #ifdef __linux__ -static int get_boot_time() -{ - int uptime; - FILE *fp = fopen ("/proc/uptime", "r"); - if (fp != NULL) - { - char buf[BUFSIZ]; - char *b = fgets(buf, BUFSIZ, fp); - if (b == buf) - { - char *end_ptr; - double upsecs = strtod(buf, &end_ptr); - uptime = (int)upsecs; - } - fclose (fp); - } - time_t now = time(NULL); - return now - uptime; -} - -int init_process_iterator(struct process_iterator *it, struct process_filter *filter) -{ - //open a directory stream to /proc directory - if ((it->dip = opendir("/proc")) == NULL) - { - perror("opendir"); - return -1; - } - it->filter = filter; - it->boot_time = get_boot_time(); - return 0; -} - -static int read_process_info(pid_t pid, struct process *p) -{ - static char buffer[1024]; - static char statfile[32]; - static char exefile[1024]; - p->pid = pid; - //read stat file - sprintf(statfile, "/proc/%d/stat", p->pid); - FILE *fd = fopen(statfile, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd)==NULL) { - fclose(fd); - return -1; - } - fclose(fd); - char *token = strtok(buffer, " "); - int i; - for (i=0; i<3; i++) token = strtok(NULL, " "); - p->ppid = atoi(token); - for (i=0; i<10; i++) - token = strtok(NULL, " "); - p->cputime = atoi(token) * 1000 / HZ; - token = strtok(NULL, " "); - p->cputime += atoi(token) * 1000 / HZ; - for (i=0; i<7; i++) - token = strtok(NULL, " "); - p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); - //read command line - sprintf(exefile,"/proc/%d/cmdline", p->pid); - fd = fopen(statfile, "r"); - if (fgets(buffer, sizeof(buffer), fd)==NULL) { - fclose(fd); - return -1; - } - fclose(fd); - sscanf(buffer, "%s", (char*)&p->command); - return 0; -} - -static pid_t getppid_of(pid_t pid) -{ - char statfile[20]; - char buffer[1024]; - sprintf(statfile, "/proc/%d/stat", pid); - FILE *fd = fopen(statfile, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd)==NULL) { - fclose(fd); - return -1; - } - fclose(fd); - char *token = strtok(buffer, " "); - int i; - for (i=0; i<3; i++) token = strtok(NULL, " "); - return atoi(token); -} - -static int is_child_of(pid_t child_pid, pid_t parent_pid) -{ - int ppid = child_pid; - while(ppid > 1 && ppid != parent_pid) { - ppid = getppid_of(ppid); - } - return ppid == parent_pid; -} - -int get_next_process(struct process_iterator *it, struct process *p) -{ - if (it->dip == NULL) - { - //end of processes - return -1; - } - if (it->filter->pid > 0 && !it->filter->include_children) - { - read_process_info(it->filter->pid, p); - p->starttime += it->boot_time; - it->dip = NULL; - return 0; - } - struct dirent *dit; - //read in from /proc and seek for process dirs - while ((dit = readdir(it->dip)) != NULL) { - if(strtok(dit->d_name, "0123456789") != NULL) - continue; - p->pid = atoi(dit->d_name); - if (it->filter->pid > 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue; - read_process_info(p->pid, p); - p->starttime += it->boot_time; - break; - } - if (dit == NULL) - { - //end of processes - closedir(it->dip); - it->dip = NULL; - return -1; - } - return 0; -} - -int close_process_iterator(struct process_iterator *it) { - if (it->dip != 0 && closedir(it->dip) == -1) { - perror("closedir"); - return 1; - } - it->dip = NULL; - return 0; -} +#include "process_iterator_linux.c" #elif defined __FreeBSD__ -#include -#include -#include -#include - -int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { - kvm_t *kd; - char errbuf[_POSIX2_LINE_MAX]; - it->i = 0; - /* Open the kvm interface, get a descriptor */ - if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { - /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: %s", errbuf); - return -1; - } - /* Get the list of processes. */ - if ((it->procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { - kvm_close(kd); - /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); - return -1; - } - kvm_close(kd); - it->filter = filter; - return 0; -} - -static void kproc2proc(struct kinfo_proc *kproc, struct process *proc) -{ - proc->pid = kproc->ki_pid; - proc->ppid = kproc->ki_ppid; - proc->cputime = kproc->ki_runtime / 1000; - proc->starttime = kproc->ki_start.tv_sec; -} - -static int get_single_process(pid_t pid, struct process *process) -{ - kvm_t *kd; - int count; - char errbuf[_POSIX2_LINE_MAX]; - /* Open the kvm interface, get a descriptor */ - if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { - /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: %s", errbuf); - return -1; - } - struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); - kvm_close(kd); - if (count == 0 || kproc == NULL) - { - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); - return -1; - } - kproc2proc(kproc, process); - return 0; -} - -int get_next_process(struct process_iterator *it, struct process *p) { - if (it->i == it->count) - { - return -1; - } - if (it->filter->pid > 0 && !it->filter->include_children) - { - get_single_process(it->filter->pid, p); - it->i = it->count = 1; - return 0; - } - while (it->i < it->count) - { - if (it->filter->pid > 0 && it->filter->include_children) - { - kproc2proc(&(it->procs[it->i]), p); - it->i++; - if (p->pid != it->filter->pid && p->ppid != it->filter->pid) - continue; - return 0; - } - else if (it->filter->pid == 0) - { - kproc2proc(&(it->procs[it->i]), p); - it->i++; - return 0; - } - } - return -1; -} - -int close_process_iterator(struct process_iterator *it) { - return 0; -} +#include "process_iterator_freebsd.c" #elif defined __APPLE__ -int init_process_iterator(struct process_iterator *it) { - return 0; -} - -int get_next_process(struct process_iterator *it, struct process *p) { - return -1; -} - -int close_process_iterator(struct process_iterator *it) { - return 0; -} - - // int err; - // struct kinfo_proc *result = NULL; - // size_t length; - // int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; - - // /* We start by calling sysctl with result == NULL and length == 0. - // That will succeed, and set length to the appropriate length. - // We then allocate a buffer of that size and call sysctl again - // with that buffer. - // */ - // length = 0; - // err = sysctl(mib, 4, NULL, &length, NULL, 0); - // if (err == -1) { - // err = errno; - // } - // if (err == 0) { - // result = malloc(length); - // err = sysctl(mib, 4, result, &length, NULL, 0); - // if (err == -1) - // err = errno; - // if (err == ENOMEM) { - // free(result); /* clean up */ - // result = NULL; - // } - // } +#include "process_iterator_apple.c" - // i->proclist = result; - // i->count = err == 0 ? length / sizeof *result : 0; - // i->c = 0; +#else -// int get_proc_info(struct process *p, pid_t pid) { -// int err; -// struct kinfo_proc *result = NULL; -// size_t length; -// int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - -// /* We start by calling sysctl with result == NULL and length == 0. -// That will succeed, and set length to the appropriate length. -// We then allocate a buffer of that size and call sysctl again -// with that buffer. -// */ -// length = 0; -// err = sysctl(mib, 4, NULL, &length, NULL, 0); -// if (err == -1) { -// err = errno; -// } -// if (err == 0) { -// result = malloc(length); -// err = sysctl(mib, 4, result, &length, NULL, 0); -// if (err == -1) -// err = errno; -// if (err == ENOMEM) { -// free(result); /* clean up */ -// result = NULL; -// } -// } - -// p->pid = result->kp_proc.p_pid; -// p->ppid = result->kp_eproc.e_ppid; -// p->starttime = result->kp_proc.p_starttime.tv_sec; -// p->last_jiffies = result->kp_proc.p_cpticks; -// //p_pctcpu - -// return 0; -// } - -#elif defined __APPLE__ +#error Platform not supported #endif diff --git a/src/process_iterator.h b/src/process_iterator.h index 1747644..39379b8 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -53,16 +53,14 @@ struct process { //pid of the process pid_t pid; - //pid of the process + //ppid of the process pid_t ppid; - //start time + //start time (unix timestamp) int starttime; - //cputime used by the process expressed in milliseconds + //cputime used by the process (in milliseconds) int cputime; //actual cpu usage estimation (value in range 0-1) double cpu_usage; - //1 if the process is zombie - int is_zombie; //absolute path of the executable file char command[PATH_MAX+1]; }; diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c new file mode 100644 index 0000000..ee574e7 --- /dev/null +++ b/src/process_iterator_apple.c @@ -0,0 +1,77 @@ +int init_process_iterator(struct process_iterator *it) { + return 0; +} + +int get_next_process(struct process_iterator *it, struct process *p) { + return -1; +} + +int close_process_iterator(struct process_iterator *it) { + return 0; +} + + // int err; + // struct kinfo_proc *result = NULL; + // size_t length; + // int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; + + // /* We start by calling sysctl with result == NULL and length == 0. + // That will succeed, and set length to the appropriate length. + // We then allocate a buffer of that size and call sysctl again + // with that buffer. + // */ + // length = 0; + // err = sysctl(mib, 4, NULL, &length, NULL, 0); + // if (err == -1) { + // err = errno; + // } + // if (err == 0) { + // result = malloc(length); + // err = sysctl(mib, 4, result, &length, NULL, 0); + // if (err == -1) + // err = errno; + // if (err == ENOMEM) { + // free(result); /* clean up */ + // result = NULL; + // } + // } + + // i->proclist = result; + // i->count = err == 0 ? length / sizeof *result : 0; + // i->c = 0; + +// int get_proc_info(struct process *p, pid_t pid) { +// int err; +// struct kinfo_proc *result = NULL; +// size_t length; +// int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + +// /* We start by calling sysctl with result == NULL and length == 0. +// That will succeed, and set length to the appropriate length. +// We then allocate a buffer of that size and call sysctl again +// with that buffer. +// */ +// length = 0; +// err = sysctl(mib, 4, NULL, &length, NULL, 0); +// if (err == -1) { +// err = errno; +// } +// if (err == 0) { +// result = malloc(length); +// err = sysctl(mib, 4, result, &length, NULL, 0); +// if (err == -1) +// err = errno; +// if (err == ENOMEM) { +// free(result); /* clean up */ +// result = NULL; +// } +// } + +// p->pid = result->kp_proc.p_pid; +// p->ppid = result->kp_eproc.e_ppid; +// p->starttime = result->kp_proc.p_starttime.tv_sec; +// p->last_jiffies = result->kp_proc.p_cpticks; +// //p_pctcpu + +// return 0; +// } diff --git a/src/process_iterator_freebsd.c b/src/process_iterator_freebsd.c new file mode 100644 index 0000000..fae671d --- /dev/null +++ b/src/process_iterator_freebsd.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + kvm_t *kd; + char errbuf[_POSIX2_LINE_MAX]; + it->i = 0; + /* Open the kvm interface, get a descriptor */ + if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ + fprintf(stderr, "kvm_open: %s", errbuf); + return -1; + } + /* Get the list of processes. */ + if ((it->procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { + kvm_close(kd); + /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); + return -1; + } + kvm_close(kd); + it->filter = filter; + return 0; +} + +static void kproc2proc(struct kinfo_proc *kproc, struct process *proc) +{ + proc->pid = kproc->ki_pid; + proc->ppid = kproc->ki_ppid; + proc->cputime = kproc->ki_runtime / 1000; + proc->starttime = kproc->ki_start.tv_sec; +} + +static int get_single_process(pid_t pid, struct process *process) +{ + kvm_t *kd; + int count; + char errbuf[_POSIX2_LINE_MAX]; + /* Open the kvm interface, get a descriptor */ + if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ + fprintf(stderr, "kvm_open: %s", errbuf); + return -1; + } + struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); + kvm_close(kd); + if (count == 0 || kproc == NULL) + { + fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); + return -1; + } + kproc2proc(kproc, process); + return 0; +} + +int get_next_process(struct process_iterator *it, struct process *p) { + if (it->i == it->count) + { + return -1; + } + if (it->filter->pid > 0 && !it->filter->include_children) + { + get_single_process(it->filter->pid, p); + it->i = it->count = 1; + return 0; + } + while (it->i < it->count) + { + if (it->filter->pid > 0 && it->filter->include_children) + { + kproc2proc(&(it->procs[it->i]), p); + it->i++; + if (p->pid != it->filter->pid && p->ppid != it->filter->pid) + continue; + return 0; + } + else if (it->filter->pid == 0) + { + kproc2proc(&(it->procs[it->i]), p); + it->i++; + return 0; + } + } + return -1; +} + +int close_process_iterator(struct process_iterator *it) { + return 0; +} + diff --git a/src/process_iterator_linux.c b/src/process_iterator_linux.c new file mode 100644 index 0000000..34170e9 --- /dev/null +++ b/src/process_iterator_linux.c @@ -0,0 +1,142 @@ +static int get_boot_time() +{ + int uptime; + FILE *fp = fopen ("/proc/uptime", "r"); + if (fp != NULL) + { + char buf[BUFSIZ]; + char *b = fgets(buf, BUFSIZ, fp); + if (b == buf) + { + char *end_ptr; + double upsecs = strtod(buf, &end_ptr); + uptime = (int)upsecs; + } + fclose (fp); + } + time_t now = time(NULL); + return now - uptime; +} + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) +{ + //open a directory stream to /proc directory + if ((it->dip = opendir("/proc")) == NULL) + { + perror("opendir"); + return -1; + } + it->filter = filter; + it->boot_time = get_boot_time(); + return 0; +} + +static int read_process_info(pid_t pid, struct process *p) +{ + static char buffer[1024]; + static char statfile[32]; + static char exefile[1024]; + p->pid = pid; + //read stat file + sprintf(statfile, "/proc/%d/stat", p->pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) return -1; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) token = strtok(NULL, " "); + p->ppid = atoi(token); + for (i=0; i<10; i++) + token = strtok(NULL, " "); + p->cputime = atoi(token) * 1000 / HZ; + token = strtok(NULL, " "); + p->cputime += atoi(token) * 1000 / HZ; + for (i=0; i<7; i++) + token = strtok(NULL, " "); + p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); + //read command line + sprintf(exefile,"/proc/%d/cmdline", p->pid); + fd = fopen(statfile, "r"); + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + sscanf(buffer, "%s", (char*)&p->command); + return 0; +} + +static pid_t getppid_of(pid_t pid) +{ + char statfile[20]; + char buffer[1024]; + sprintf(statfile, "/proc/%d/stat", pid); + FILE *fd = fopen(statfile, "r"); + if (fd==NULL) return -1; + if (fgets(buffer, sizeof(buffer), fd)==NULL) { + fclose(fd); + return -1; + } + fclose(fd); + char *token = strtok(buffer, " "); + int i; + for (i=0; i<3; i++) token = strtok(NULL, " "); + return atoi(token); +} + +static int is_child_of(pid_t child_pid, pid_t parent_pid) +{ + int ppid = child_pid; + while(ppid > 1 && ppid != parent_pid) { + ppid = getppid_of(ppid); + } + return ppid == parent_pid; +} + +int get_next_process(struct process_iterator *it, struct process *p) +{ + if (it->dip == NULL) + { + //end of processes + return -1; + } + if (it->filter->pid > 0 && !it->filter->include_children) + { + read_process_info(it->filter->pid, p); + //p->starttime += it->boot_time; + it->dip = NULL; + return 0; + } + struct dirent *dit; + //read in from /proc and seek for process dirs + while ((dit = readdir(it->dip)) != NULL) { + if(strtok(dit->d_name, "0123456789") != NULL) + continue; + p->pid = atoi(dit->d_name); + if (it->filter->pid > 0 && it->filter->pid != p->pid && !is_child_of(p->pid, it->filter->pid)) continue; + read_process_info(p->pid, p); + //p->starttime += it->boot_time; + break; + } + if (dit == NULL) + { + //end of processes + closedir(it->dip); + it->dip = NULL; + return -1; + } + return 0; +} + +int close_process_iterator(struct process_iterator *it) { + if (it->dip != NULL && closedir(it->dip) == -1) { + perror("closedir"); + return 1; + } + it->dip = NULL; + return 0; +} diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index dcd4ebe..566648d 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -4,29 +4,36 @@ #include #include #include +#include #include #include +volatile sig_atomic_t child; + +void kill_child(int sig) +{ + kill(child, SIGINT); +} + void test_single_process() { struct process_iterator it; struct process process; struct process_filter filter; int count; - time_t now; //don't iterate children filter.pid = getpid(); filter.include_children = 0; count = 0; - now = time(NULL); +// time_t now = time(NULL); init_process_iterator(&it, &filter); while (get_next_process(&it, &process) == 0) { assert(process.pid == getpid()); assert(process.ppid == getppid()); assert(process.cputime < 100); - assert(process.starttime == now || process.starttime == now - 1); +// assert(process.starttime == now || process.starttime == now - 1); count++; } assert(count == 1); @@ -35,14 +42,14 @@ void test_single_process() filter.pid = getpid(); filter.include_children = 0; count = 0; - now = time(NULL); +// now = time(NULL); init_process_iterator(&it, &filter); while (get_next_process(&it, &process) == 0) { assert(process.pid == getpid()); assert(process.ppid == getppid()); assert(process.cputime < 100); - assert(process.starttime == now || process.starttime == now - 1); +// assert(process.starttime == now || process.starttime == now - 1); count++; } assert(count == 1); @@ -54,29 +61,30 @@ void test_multiple_process() struct process_iterator it; struct process process; struct process_filter filter; - int child = fork(); + pid_t child = fork(); if (child == 0) { - //child code + //child is supposed to be killed by the parent :/ sleep(1); - exit(0); + exit(1); } filter.pid = getpid(); filter.include_children = 1; init_process_iterator(&it, &filter); int count = 0; - time_t now = time(NULL); +// time_t now = time(NULL); while (get_next_process(&it, &process) == 0) { if (process.pid == getpid()) assert(process.ppid == getppid()); else if (process.pid == child) assert(process.ppid == getpid()); else assert(0); assert(process.cputime < 100); - assert(process.starttime == now || process.starttime == now - 1); +// assert(process.starttime == now || process.starttime == now - 1); count++; } assert(count == 2); close_process_iterator(&it); + kill(child, SIGINT); } void test_all_processes() @@ -87,14 +95,14 @@ void test_all_processes() filter.pid = 0; init_process_iterator(&it, &filter); int count = 0; - time_t now = time(NULL); +// time_t now = time(NULL); while (get_next_process(&it, &process) == 0) { if (process.pid == getpid()) { assert(process.ppid == getppid()); assert(process.cputime < 100); - assert(process.starttime == now || process.starttime == now - 1); +// assert(process.starttime == now || process.starttime == now - 1); } count++; } @@ -102,21 +110,65 @@ void test_all_processes() close_process_iterator(&it); } -void test_process_list() +void test_process_group_all() { struct process_group pgroup; - pid_t current_pid = getpid(); - assert(init_process_group(&pgroup, current_pid, 0) == 0); + assert(init_process_group(&pgroup, 0, 0) == 0); + update_process_group(&pgroup); + struct list_node *node = NULL; + int count = 0; + for (node=pgroup.proclist->first; node!= NULL; node=node->next) { + count++; + } + assert(count > 10); update_process_group(&pgroup); assert(close_process_group(&pgroup) == 0); } +void test_process_group_single() +{ + struct process_group pgroup; + child = fork(); + if (child == 0) + { + //child is supposed to be killed by the parent :/ + while(1); + exit(1); + } + signal(SIGABRT, &kill_child); + signal(SIGTERM, &kill_child); + assert(init_process_group(&pgroup, child, 0) == 0); + int i; + for (i=0; i<10000; i++) + { + update_process_group(&pgroup); + struct list_node *node = NULL; + int count = 0; + for (node=pgroup.proclist->first; node!= NULL; node=node->next) { + struct process *p = (struct process*)(node->data); + assert(p->pid == child); + assert(p->ppid == getpid()); + assert(p->cpu_usage <= 1.2); +printf("%f\n", p->cpu_usage); + count++; + } + assert(count == 1); + struct timespec interval; + interval.tv_sec = 0; + interval.tv_nsec = 100000000; + nanosleep(&interval, NULL); + } + assert(close_process_group(&pgroup) == 0); + kill(child, SIGINT); +} + int main() { - printf("Pid %d\n", getpid()); +// printf("Pid %d\n", getpid()); test_single_process(); test_multiple_process(); test_all_processes(); - test_process_list(); + test_process_group_all(); + test_process_group_single(); return 0; } -- cgit v1.2.3 From 622bdab1e23bf95d5ed725b5db8ef2cf86d42cb2 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Thu, 21 Jun 2012 02:27:11 +0100 Subject: removed file descriptor leak --- src/process_iterator_linux.c | 1 + tests/process_iterator_test.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/process_iterator_linux.c b/src/process_iterator_linux.c index 34170e9..da3fb07 100644 --- a/src/process_iterator_linux.c +++ b/src/process_iterator_linux.c @@ -108,6 +108,7 @@ int get_next_process(struct process_iterator *it, struct process *p) { read_process_info(it->filter->pid, p); //p->starttime += it->boot_time; + closedir(it->dip); it->dip = NULL; return 0; } diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 566648d..e4d84fd 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -137,7 +137,7 @@ void test_process_group_single() } signal(SIGABRT, &kill_child); signal(SIGTERM, &kill_child); - assert(init_process_group(&pgroup, child, 0) == 0); + assert(init_process_group(&pgroup, child, 1) == 0); int i; for (i=0; i<10000; i++) { -- cgit v1.2.3 From eccc7f8368982422fb15287be27bdd83567d0e8c Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Thu, 21 Jun 2012 23:34:09 +0100 Subject: fixed arithmetic bug --- src/process_group.c | 48 ++++++------------------------------------- tests/process_iterator_test.c | 15 ++++++++------ 2 files changed, 15 insertions(+), 48 deletions(-) diff --git a/src/process_group.c b/src/process_group.c index 043ee69..318babb 100644 --- a/src/process_group.c +++ b/src/process_group.c @@ -54,41 +54,6 @@ static inline unsigned long timediff(const struct timeval *t1,const struct timev //parameter in range 0-1 #define ALFA 0.08 -int process_monitor(struct process *proc) -{ - // int j = get_jiffies(proc); - // if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead) - // struct timeval now; - // gettimeofday(&now, NULL); - // if (proc->last_jiffies==-1) { - // //store current time - // proc->last_sample = now; - // //store current jiffies - // proc->last_jiffies = j; - // //it's the first sample, cannot figure out the cpu usage - // proc->cpu_usage = -1; - // return 0; - // } - // //time from previous sample (in ns) - // long dt = timediff(&now, &(proc->last_sample)); - // //how many jiffies in dt? - // double max_jiffies = dt * HZ / 1000000.0; - // double sample = (j - proc->last_jiffies) / max_jiffies; - // if (proc->cpu_usage == -1) { - // //initialization - // proc->cpu_usage = sample; - // } - // else { - // //usage adjustment - // proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample; - // } - // //store current time - // proc->last_sample = now; - // //store current jiffies - // proc->last_jiffies = j; - return 0; -} - void update_process_group(struct process_group *pgroup) { struct process_iterator it; @@ -105,10 +70,9 @@ void update_process_group(struct process_group *pgroup) long dt = timediff(&now, &pgroup->last_update) / 1000; while (get_next_process(&it, &tmp_process) != -1) { - // printf("Read process %d\n", tmp_process.pid); - // printf("Parent %d\n", tmp_process.ppid); - // printf("Starttime %d\n", tmp_process.starttime); - // printf("CPU time %d\n", tmp_process.cputime); +// struct timeval t; +// gettimeofday(&t, NULL); +// printf("T=%ld.%ld PID=%d PPID=%d START=%d CPUTIME=%d\n", t.tv_sec, t.tv_usec, tmp_process.pid, tmp_process.ppid, tmp_process.starttime, tmp_process.cputime); int hashkey = pid_hashfn(tmp_process.pid + tmp_process.starttime); if (pgroup->proctable[hashkey] == NULL) { @@ -140,16 +104,16 @@ void update_process_group(struct process_group *pgroup) assert(tmp_process.ppid == p->ppid); assert(tmp_process.starttime == p->starttime); //process exists. update CPU usage - double sample = (tmp_process.cputime - p->cputime) / dt; + double sample = 1.0 * (tmp_process.cputime - p->cputime) / dt; if (p->cpu_usage == -1) { //initialization p->cpu_usage = sample; } else { //usage adjustment - p->cpu_usage = (1-ALFA) * p->cpu_usage + ALFA * sample; + p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample; } - p->cpu_usage = (1-ALFA) * p->cpu_usage + ALFA * sample; + p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample; p->cputime = tmp_process.cputime; add_elem(pgroup->proclist, p); } diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index e4d84fd..487d7ea 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -125,7 +125,7 @@ void test_process_group_all() assert(close_process_group(&pgroup) == 0); } -void test_process_group_single() +void test_process_group_single(int include_children) { struct process_group pgroup; child = fork(); @@ -137,9 +137,10 @@ void test_process_group_single() } signal(SIGABRT, &kill_child); signal(SIGTERM, &kill_child); - assert(init_process_group(&pgroup, child, 1) == 0); + assert(init_process_group(&pgroup, child, include_children) == 0); int i; - for (i=0; i<10000; i++) + double tot_usage = 0; + for (i=0; i<100; i++) { update_process_group(&pgroup); struct list_node *node = NULL; @@ -149,15 +150,16 @@ void test_process_group_single() assert(p->pid == child); assert(p->ppid == getpid()); assert(p->cpu_usage <= 1.2); -printf("%f\n", p->cpu_usage); + tot_usage += p->cpu_usage; count++; } assert(count == 1); struct timespec interval; interval.tv_sec = 0; - interval.tv_nsec = 100000000; + interval.tv_nsec = 50000000; nanosleep(&interval, NULL); } + assert(tot_usage / i < 1.1 && tot_usage / i > 0.9); assert(close_process_group(&pgroup) == 0); kill(child, SIGINT); } @@ -169,6 +171,7 @@ int main() test_multiple_process(); test_all_processes(); test_process_group_all(); - test_process_group_single(); + test_process_group_single(0); + test_process_group_single(1); return 0; } -- cgit v1.2.3 From e01adfd46264d634009f0c3fe1e0f5936afffbd1 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Fri, 22 Jun 2012 01:55:53 +0100 Subject: cpulimit.c integrated with the new changes --- src/Makefile | 13 +- src/cpulimit.c | 149 ++++--------- src/process_group.c | 93 +++++++- src/process_group.h | 4 + src/process_iterator_freebsd.c | 1 + src/process_iterator_linux.c | 20 +- src/procutils.c | 469 ----------------------------------------- tests/process_iterator_test.c | 24 ++- 8 files changed, 179 insertions(+), 594 deletions(-) delete mode 100644 src/procutils.c diff --git a/src/Makefile b/src/Makefile index e6e819f..86fbfbd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,6 @@ CC?=gcc CFLAGS?=-Wall -g -D_GNU_SOURCE TARGETS=cpulimit -#LIBS=procutils.o list.o process_iterator.o LIBS=list.o process_iterator.o process_group.o UNAME := $(shell uname) @@ -10,10 +9,10 @@ ifeq ($(UNAME), FreeBSD) LIBS+=-lkvm endif -all:: $(LIBS) +all:: $(TARGETS) $(LIBS) -#cpulimit: cpulimit.c $(LIBS) -# $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) +cpulimit: cpulimit.c $(LIBS) + $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS) process_iterator.o: process_iterator.c process_iterator.h $(CC) -c process_iterator.c $(CFLAGS) @@ -24,12 +23,6 @@ list.o: list.c list.h process_group.o: process_group.c process_group.h process_iterator.o list.o $(CC) -c process_group.c $(CFLAGS) -#process.o: process.c process.h -# $(CC) -c process.c $(CFLAGS) - -#procutils.o: procutils.c procutils.h -# $(CC) -c procutils.c $(CFLAGS) - clean: rm -f *~ *.o $(TARGETS) diff --git a/src/cpulimit.c b/src/cpulimit.c index 6126c6b..394b132 100644 --- a/src/cpulimit.c +++ b/src/cpulimit.c @@ -61,8 +61,7 @@ #include #include -#include "process.h" -#include "procutils.h" +#include "process_group.h" #include "list.h" //some useful macro @@ -83,7 +82,7 @@ /* GLOBAL VARIABLES */ //the "family" -struct process_family pf; +struct process_group pgroup; //pid of cpulimit pid_t cpulimit_pid; //name of this program (maybe cpulimit...) @@ -104,13 +103,11 @@ static void quit(int sig) { //let all the processes continue if stopped struct list_node *node = NULL; - for (node=pf.members.first; node!= NULL; node=node->next) { + for (node=pgroup.proclist->first; node!= NULL; node=node->next) { struct process *p = (struct process*)(node->data); kill(p->pid, SIGCONT); - process_close(p); } - //free all the memory - cleanup_process_family(&pf); + close_process_group(&pgroup); //fix ^C little problem printf("\r"); fflush(stdout); @@ -168,22 +165,7 @@ static int get_ncpu() { return ncpu; } -#ifdef __linux__ - -#include - -static int check_proc() -{ - struct statfs mnt; - if (statfs("/proc", &mnt) < 0) - return 0; - if (mnt.f_type!=0x9fa0) - return 0; - return 1; -} -#endif - -void limit_process(pid_t pid, double limit, int ignore_children) +void limit_process(pid_t pid, double limit, int include_children) { //slice of the slot in which the process is allowed to run struct timespec twork; @@ -209,39 +191,17 @@ void limit_process(pid_t pid, double limit, int ignore_children) increase_priority(); //build the family - create_process_family(&pf, pid); - if (ignore_children) { - //delete any process with a different pid than the father - for (node=pf.members.first; node!=NULL; node=node->next) { - struct process *proc = (struct process*)(node->data); - if (proc->pid != pid) - remove_process_from_family(&pf, proc->pid); - } - } - - if (!ignore_children && verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count); + init_process_group(&pgroup, pid, include_children); + + if (verbose) printf("Members in the process group owned by %d: %d\n", pgroup.target_pid, pgroup.proclist->count); //rate at which we are keeping active the processes (range 0-1) //1 means that the process are using all the twork slice double workingrate = -1; while(1) { - if (!ignore_children && c%10==0) { - //update the process family (checks only for new members) - int new_children = update_process_family(&pf); - if (verbose && new_children) { - printf("%d new children processes detected (", new_children); - int j; - node = pf.members.last; - for (j=0; jdata))->pid); - if (jprevious; - } - printf(")\n"); - } - } + update_process_group(&pgroup); - if (pf.members.count==0) { + if (pgroup.proclist->count==0) { if (verbose) printf("No more processes.\n"); break; } @@ -251,24 +211,12 @@ void limit_process(pid_t pid, double limit, int ignore_children) double pcpu = -1; //estimate how much the controlled processes are using the cpu in the working interval - for (node=pf.members.first; node!=NULL; node=node->next) { + for (node = pgroup.proclist->first; node != NULL; node = node->next) { struct process *proc = (struct process*)(node->data); - if (proc->is_zombie) { - //process is zombie, remove it from family - fprintf(stderr,"Process %d is zombie!\n", proc->pid); - remove_process_from_family(&pf, proc->pid); - continue; - } - if (process_monitor(proc) != 0) { - //process is dead, remove it from family - if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid); - remove_process_from_family(&pf, proc->pid); - continue; - } - if (proc->cpu_usage<0) { + if (proc->cpu_usage < 0) { continue; } - if (pcpu<0) pcpu = 0; + if (pcpu < 0) pcpu = 0; pcpu += proc->cpu_usage; } @@ -277,52 +225,52 @@ void limit_process(pid_t pid, double limit, int ignore_children) //it's the 1st cycle, initialize workingrate pcpu = limit; workingrate = limit; - twork.tv_nsec = TIME_SLOT*limit*1000; + twork.tv_nsec = TIME_SLOT * limit * 1000; } else { //adjust workingrate workingrate = MIN(workingrate / pcpu * limit, 1); - twork.tv_nsec = TIME_SLOT*1000*workingrate; + twork.tv_nsec = TIME_SLOT * 1000 * workingrate; } - tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec; + tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec; if (verbose) { if (c%200==0) printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n"); if (c%10==0 && c>0) - printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100); + printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n", pcpu*100, twork.tv_nsec/1000, tsleep.tv_nsec/1000, workingrate*100); } //resume processes - for (node=pf.members.first; node!=NULL; node=node->next) { + for (node = pgroup.proclist->first; node != NULL; node = node->next) { struct process *proc = (struct process*)(node->data); if (kill(proc->pid,SIGCONT)!=0) { //process is dead, remove it from family - if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid); - remove_process_from_family(&pf, proc->pid); + if (verbose) fprintf(stderr, "Process %d dead!\n", proc->pid); + //remove_process_from_family(&pf, proc->pid); } } //now processes are free to run (same working slice for all) gettimeofday(&startwork, NULL); - nanosleep(&twork,NULL); + nanosleep(&twork, NULL); gettimeofday(&endwork, NULL); - workingtime = timediff(&endwork,&startwork); + workingtime = timediff(&endwork, &startwork); - long delay = workingtime-twork.tv_nsec/1000; + long delay = workingtime - twork.tv_nsec/1000; if (c>0 && delay>10000) { //delay is too much! signal to user? //fprintf(stderr, "%d %ld us\n", c, delay); } if (tsleep.tv_nsec>0) { - //stop only if tsleep>0, instead it's useless - for (node=pf.members.first; node!=NULL; node=node->next) { + //stop only if tsleep>0 + for (node = pgroup.proclist->first; node != NULL; node = node->next) { struct process *proc = (struct process*)(node->data); if (kill(proc->pid,SIGSTOP)!=0) { //process is dead, remove it from family if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid); - remove_process_from_family(&pf, proc->pid); + //remove_process_from_family(&pf, proc->pid); } } //now the processes are sleeping @@ -330,7 +278,7 @@ void limit_process(pid_t pid, double limit, int ignore_children) } c++; } - cleanup_process_family(&pf); + close_process_group(&pgroup); } int main(int argc, char **argv) { @@ -344,8 +292,8 @@ int main(int argc, char **argv) { int ignore_children = 0; //get program name - char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0])); - program_name = p==NULL?argv[0]:(p+1); + char *p = (char*)memrchr(argv[0], (unsigned int)'/', strlen(argv[0])); + program_name = p==NULL ? argv[0] : (p+1); //get current pid cpulimit_pid = getpid(); //get cpu count @@ -405,12 +353,12 @@ int main(int argc, char **argv) { } } while(next_option != -1); - if (pid_ok && (pid<=1 || pid>=65536)) { + if (pid_ok && (pid <= 1 || pid >= 65536)) { fprintf(stderr,"Error: Invalid value for argument PID\n"); print_usage(stderr, 1); exit(1); } - if (pid!=0) { + if (pid != 0) { lazy = 1; } @@ -419,14 +367,14 @@ int main(int argc, char **argv) { print_usage(stderr, 1); exit(1); } - double limit = perclimit/100.0; + double limit = perclimit / 100.0; if (limit<0 || limit >NCPU) { fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU); print_usage(stderr, 1); exit(1); } - int command_mode = optind 0) { + else if (child == 0) { + //target process code + int ret = execvp(cmd, cmd_args); + //if we are here there was an error, show it + perror("Error"); + exit(ret); + } + else { //parent code free(cmd_args); int limiter = fork(); @@ -504,13 +452,6 @@ int main(int argc, char **argv) { exit(0); } } - else { - //target process code - int ret = execvp(cmd, cmd_args); - //if we are here there was an error, show it - perror("Error"); - exit(ret); - } } while(1) { @@ -518,7 +459,7 @@ int main(int argc, char **argv) { pid_t ret = 0; if (pid_ok) { //search by pid - ret = look_for_process_by_pid(pid); + ret = find_process_by_pid(pid); if (ret == 0) { printf("No process found\n"); } @@ -528,7 +469,7 @@ int main(int argc, char **argv) { } else { //search by file or path name - ret = look_for_process_by_name(exe); + ret = find_process_by_name(exe); if (ret == 0) { printf("No process found\n"); } @@ -541,7 +482,7 @@ int main(int argc, char **argv) { } if (ret > 0) { if (ret == cpulimit_pid) { - printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret); + printf("Target process %d is cpulimit itself! Aborting because it makes no sense\n", ret); exit(1); } printf("Process %d found\n", pid); diff --git a/src/process_group.c b/src/process_group.c index 318babb..71f180b 100644 --- a/src/process_group.c +++ b/src/process_group.c @@ -1,8 +1,8 @@ -#include #include #include #include #include +#include #include @@ -10,6 +10,81 @@ #include "process_group.h" #include "list.h" +// look for a process by pid +// search_pid : pid of the wanted process +// return: pid of the found process, if successful +// negative pid, if the process does not exist or if the signal fails +int find_process_by_pid(pid_t pid) +{ + return (kill(pid,0)==0) ? pid : -pid; +} + +// look for a process with a given name +// process: the name of the wanted process. it can be an absolute path name to the executable file +// or just the file name +// return: pid of the found process, if it is found +// 0, if it's not found +// negative pid, if it is found but it's not possible to control it +int find_process_by_name(const char *process_name) +{ + //whether the variable process_name is the absolute path or not + int is_absolute_path = process_name[0] == '/'; + //flag indicating if the a process with given name was found + int found = 0; + pid_t pid = -1; + + //process iterator + struct process_iterator it; + struct process proc; + struct process_filter filter; + filter.pid = 0; + filter.include_children = 0; + init_process_iterator(&it, &filter); + while (get_next_process(&it, &proc) != -1) + { + pid = proc.pid; + int size = strlen(proc.command); + + found = 0; + if (is_absolute_path && strncmp(proc.command, process_name, size)==0 && size==strlen(process_name)) { + //process found + found = 1; + } + else { + //process found + if (strncmp(proc.command + size - strlen(process_name), process_name, strlen(process_name))==0) { + found = 1; + } + } + if (found==1) { + if (kill(pid,SIGCONT)==0) { + //process is ok! + break; + } + else { + //we don't have permission to send signal to that process + //so, don't exit from the loop and look for another one with the same name + found = -1; + } + } + } + if (close_process_iterator(&it) != 1) exit(1); + if (found == 1) { + //ok, the process was found + return pid; + } + else if (found == 0) { + //no process found + return 0; + } + else if (found == -1) { + //the process was found, but we haven't permission to control it + return -pid; + } + //this MUST NOT happen + exit(2); +} + int init_process_group(struct process_group *pgroup, int target_pid, int include_children) { //hashtable initialization @@ -19,6 +94,7 @@ int init_process_group(struct process_group *pgroup, int target_pid, int include pgroup->proclist = (struct list*)malloc(sizeof(struct list)); init_list(pgroup->proclist, 4); memset(&pgroup->last_update, 0, sizeof(pgroup->last_update)); + update_process_group(pgroup); return 0; } @@ -53,21 +129,23 @@ static inline unsigned long timediff(const struct timeval *t1,const struct timev //parameter in range 0-1 #define ALFA 0.08 +#define MIN_DT 20 void update_process_group(struct process_group *pgroup) { struct process_iterator it; struct process tmp_process; struct process_filter filter; + struct timeval now; + gettimeofday(&now, NULL); + //time elapsed from previous sample (in ms) + long dt = timediff(&now, &pgroup->last_update) / 1000; filter.pid = pgroup->target_pid; filter.include_children = pgroup->include_children; init_process_iterator(&it, &filter); clear_list(pgroup->proclist); init_list(pgroup->proclist, 4); - struct timeval now; - gettimeofday(&now, NULL); - //time elapsed from previous sample (in ms) - long dt = timediff(&now, &pgroup->last_update) / 1000; + while (get_next_process(&it, &tmp_process) != -1) { // struct timeval t; @@ -103,6 +181,8 @@ void update_process_group(struct process_group *pgroup) assert(tmp_process.pid == p->pid); assert(tmp_process.ppid == p->ppid); assert(tmp_process.starttime == p->starttime); + add_elem(pgroup->proclist, p); + if (dt < MIN_DT) continue; //process exists. update CPU usage double sample = 1.0 * (tmp_process.cputime - p->cputime) / dt; if (p->cpu_usage == -1) { @@ -113,12 +193,11 @@ void update_process_group(struct process_group *pgroup) //usage adjustment p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample; } - p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample; p->cputime = tmp_process.cputime; - add_elem(pgroup->proclist, p); } } } close_process_iterator(&it); + if (dt < MIN_DT) return; pgroup->last_update = now; } diff --git a/src/process_group.h b/src/process_group.h index f26d2cb..100711d 100644 --- a/src/process_group.h +++ b/src/process_group.h @@ -46,4 +46,8 @@ void update_process_group(struct process_group *pgroup); int close_process_group(struct process_group *pgroup); +int find_process_by_pid(pid_t pid); + +int find_process_by_name(const char *process_name); + #endif diff --git a/src/process_iterator_freebsd.c b/src/process_iterator_freebsd.c index fae671d..e840968 100644 --- a/src/process_iterator_freebsd.c +++ b/src/process_iterator_freebsd.c @@ -31,6 +31,7 @@ static void kproc2proc(struct kinfo_proc *kproc, struct process *proc) proc->ppid = kproc->ki_ppid; proc->cputime = kproc->ki_runtime / 1000; proc->starttime = kproc->ki_start.tv_sec; + memcpy(proc->command, kproc->ki_comm, strlen(kproc->ki_comm)); } static int get_single_process(pid_t pid, struct process *process) diff --git a/src/process_iterator_linux.c b/src/process_iterator_linux.c index da3fb07..a15be45 100644 --- a/src/process_iterator_linux.c +++ b/src/process_iterator_linux.c @@ -1,3 +1,5 @@ +#include + static int get_boot_time() { int uptime; @@ -18,8 +20,22 @@ static int get_boot_time() return now - uptime; } +static int check_proc() +{ + struct statfs mnt; + if (statfs("/proc", &mnt) < 0) + return 0; + if (mnt.f_type!=0x9fa0) + return 0; + return 1; +} + int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + 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) { @@ -60,13 +76,13 @@ static int read_process_info(pid_t pid, struct process *p) p->starttime = atoi(token) / sysconf(_SC_CLK_TCK); //read command line sprintf(exefile,"/proc/%d/cmdline", p->pid); - fd = fopen(statfile, "r"); + fd = fopen(exefile, "r"); if (fgets(buffer, sizeof(buffer), fd)==NULL) { fclose(fd); return -1; } fclose(fd); - sscanf(buffer, "%s", (char*)&p->command); + sscanf(buffer, "%s", p->command); return 0; } diff --git a/src/procutils.c b/src/procutils.c deleted file mode 100644 index 7367196..0000000 --- a/src/procutils.c +++ /dev/null @@ -1,469 +0,0 @@ -/** - * - * cpulimit - a cpu limiter for Linux - * - * Copyright (C) 2005-2008, by: Angelo Marletta - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "procutils.h" - -#ifdef __APPLE__ -#include -#include -#endif - -#ifdef __FreeBSD__ -#include -#endif - -/* PROCESS STATISTICS FUNCTIONS */ - -//deprecated -// returns pid of the parent process -static pid_t getppid_of(pid_t pid) -{ -#ifdef __linux__ - char file[20]; - char buffer[1024]; - sprintf(file, "/proc/%d/stat", pid); - FILE *fd = fopen(file, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd)==NULL) return -1; - fclose(fd); - char *p = buffer; - p = memchr(p+1,')', sizeof(buffer) - (p-buffer)); - int sp = 2; - while (sp--) - p = memchr(p+1,' ',sizeof(buffer) - (p-buffer)); - //pid of the parent process - pid_t ppid = atoi(p+1); - return ppid; -#elif defined __APPLE__ - struct process p; - get_proc_info(&p, pid); - return p.ppid; -#elif defined __FreeBSD__ - -#endif -} - -#ifdef __linux__ -// detects whether a process is a kernel thread or not -static int is_kernel_thread(pid_t pid) -{ - static char statfile[20]; - static char buffer[64]; - int ret; - sprintf(statfile, "/proc/%d/statm", pid); - FILE *fd = fopen(statfile, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd)==NULL) return -1; - ret = strncmp(buffer,"0 0 0",3)==0; - fclose(fd); - return ret; -} -#endif - -/* PID HASH FUNCTIONS */ - -static int hash_process(struct process_family *f, struct process *p) -{ - int ret; - struct list **l = &(f->proctable[pid_hashfn(p->pid)]); - if (*l == NULL) { - //there is no process in this hashtable item - //allocate the list - *l = (struct list*)malloc(sizeof(struct list)); - init_list(*l, 4); - add_elem(*l, p); - ret = 0; - f->count++; - } - else { - //list already exists - struct process *tmp = (struct process*)locate_elem(*l, p); - if (tmp != NULL) { - //update process info - memcpy(tmp, p, sizeof(struct process)); - free(p); - p = NULL; - ret = 1; - } - else { - //add new process - add_elem(*l, p); - ret = 0; - f->count++; - } - } - return ret; -} - -static void unhash_process(struct process_family *f, pid_t pid) { - //remove process from hashtable - struct list **l = &(f->proctable[pid_hashfn(pid)]); - if (*l == NULL) - return; //nothing done - struct list_node *node = locate_node(*l, &pid); - if (node != NULL) - destroy_node(*l, node); - f->count--; -} - -static struct process *seek_process(struct process_family *f, pid_t pid) -{ - struct list **l = &(f->proctable[pid_hashfn(pid)]); - return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL; -} - -/* PROCESS ITERATOR STUFF */ - -// creates an object that browse all running processes -int init_process_iterator(struct process_iterator *i) { -#ifdef __linux__ - //open a directory stream to /proc directory - if ((i->dip = opendir("/proc")) == NULL) { - perror("opendir"); - return -1; - } -#elif defined __APPLE__ - - int err; - struct kinfo_proc *result = NULL; - size_t length; - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; - - /* We start by calling sysctl with result == NULL and length == 0. - That will succeed, and set length to the appropriate length. - We then allocate a buffer of that size and call sysctl again - with that buffer. - */ - length = 0; - err = sysctl(mib, 4, NULL, &length, NULL, 0); - if (err == -1) { - err = errno; - } - if (err == 0) { - result = malloc(length); - err = sysctl(mib, 4, result, &length, NULL, 0); - if (err == -1) - err = errno; - if (err == ENOMEM) { - free(result); /* clean up */ - result = NULL; - } - } - - i->procList = result; - i->count = err == 0 ? length / sizeof *result : 0; - i->c = 0; -#elif defined __FreeBSD__ - kvm_t *kd; - struct kinfo_proc *procs = NULL; - char errbuf[_POSIX2_LINE_MAX]; - int count; - /* Open the kvm interface, get a descriptor */ - if ((kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) { - /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: %s", errbuf); - } - /* Get the list of processes. */ - if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) { - kvm_close(kd); - /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); - } - -#endif - i->current = (struct process*)calloc(1, sizeof(struct process)); - return 0; -} - -int close_process_iterator(struct process_iterator *i) { -#ifdef __linux__ - if (closedir(i->dip) == -1) { - perror("closedir"); - return 1; - } -#elif defined __APPLE__ - //TODO -#endif - return 0; -} - -// reads the next user process from /process -// automatic closing if the end of the list is reached -int read_next_process(struct process_iterator *i) { -#ifdef __linux__ - pid_t pid = 0; -//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85 - //read in from /proc and seek for process dirs - while ((i->dit = readdir(i->dip)) != NULL) { - if(strtok(i->dit->d_name, "0123456789") != NULL) - continue; - pid = atoi(i->dit->d_name); - if (is_kernel_thread(pid)) - continue; - //return the first found process - break; - } - if (pid == 0) { - //no more processes - closedir(i->dip); - free(i->current); - i->current = NULL; - return -1; - } - //read the executable link - char statfile[20]; - sprintf(statfile,"/proc/%d/cmdline",pid); - FILE *fd = fopen(statfile, "r"); - if (fd == NULL) return -1; - char buffer[1024]; - if (fgets(buffer, sizeof(buffer), fd)==NULL) return -2; - fclose(fd); - sscanf(buffer, "%s", (char*)&i->current->command); - i->current->pid = pid; - -#elif defined __APPLE__ - if (i->c >= i->count) { - //no more processes - free(i->procList); - i->procList = NULL; - free(i->current); - i->current = NULL; - return -1; - } - i->current->pid = i->procList[i->c].kp_proc.p_pid; - strncpy(i->current->command, i->procList[i->c].kp_proc.p_comm, MAXCOMLEN); -printf("%d %d %s\n", i->c, i->current->pid, i->current->command);//i->procList[i->c].kp_proc.p_comm); -//printf("%d %d %s\n", i->c, i->current->pid, i->proc[i->c].kp_proc.p_comm); - i->c++; -#endif - return 0; -} - -/* PUBLIC FUNCTIONS */ - -// search for all the processes derived from father and stores them -// in the process family struct -int create_process_family(struct process_family *f, pid_t father) -{ - //process list initialization (4 bytes key) - init_list(&(f->members), 4); - //hashtable initialization - memset(&(f->proctable), 0, sizeof(f->proctable)); - f->count = 0; - f->father = father; - //process iterator - struct process_iterator iter; - init_process_iterator(&iter); - int pid = 0; - while (read_next_process(&iter)==0) { - pid = iter.current->pid; - //check if process belongs to the family - int ppid = pid; - //TODO: optimize adding also these parents, and continue if process is already present - while(ppid!=1 && ppid!=father) { - ppid = getppid_of(ppid); - } - //allocate process descriptor - struct process *p = (struct process*)calloc(1, sizeof(struct process)); - //init process - process_init(p, pid); - if (ppid==1) { - //the init process - p->member = 0; - } - else if (pid != getpid()) { - //add to members (but exclude the current cpulimit process!) - p->member = 1; - add_elem(&(f->members), p); - } - //add to hashtable - hash_process(f, p); - } - return 0; -} - -// checks if there are new processes born in the specified family -// if any they are added to the members list -// the number of new born processes is returned -int update_process_family(struct process_family *f) -{ - int ret = 0; - //process iterator - struct process_iterator iter; - init_process_iterator(&iter); - int pid = 0; - while (read_next_process(&iter)==0) { - pid = iter.current->pid; - struct process *newp = seek_process(f, pid); - if (newp != NULL) continue; //already known //TODO: what if newp is a new process with the same PID?? - //the process is new, check if it belongs to the family - int ppid = getppid_of(pid); - //search the youngest known ancestor of the process - struct process *ancestor = NULL; - while((ancestor=seek_process(f, ppid))==NULL) { - ppid = getppid_of(ppid); - } - if (ancestor == NULL) { - //this should never happen! if does, find and correct the bug - fprintf(stderr, "Fatal bug! Process %d is without parent\n", pid); - exit(1); - } - //allocate and insert the process - struct process *p = (struct process*)calloc(1, sizeof(struct process)); - //init process - process_init(p, pid); - if (ancestor->member) { - //add to members - p->member = 1; - add_elem(&(f->members), p); - ret++; - } - else { - //not a member - p->member = 0; - } - //add to hashtable - hash_process(f, p); - } - return ret; -} - -// removes a process from the family by its pid -void remove_process_from_family(struct process_family *f, pid_t pid) -{ - struct list_node *node = locate_node(&(f->members), &pid); - if (node != NULL) { -// struct process *p = (struct process*)(node->data); -// free(p->history); -// p->history = NULL; - delete_node(&(f->members), node); - } - unhash_process(f, pid); -} - -// free the heap memory used by a process family -void cleanup_process_family(struct process_family *f) -{ - int i; - int size = sizeof(f->proctable) / sizeof(struct process*); - for (i=0; iproctable[i] != NULL) { - //free() history for each process - struct list_node *node = NULL; - for (node=f->proctable[i]->first; node!=NULL; node=node->next) { -// struct process *p = (struct process*)(node->data); -// free(p->history); -// p->history = NULL; - } - destroy_list(f->proctable[i]); - free(f->proctable[i]); - f->proctable[i] = NULL; - } - } - flush_list(&(f->members)); - f->count = 0; - f->father = 0; -} - -// look for a process by pid -// search_pid : pid of the wanted process -// return: pid of the found process, if successful -// negative pid, if the process does not exist or if the signal fails -int look_for_process_by_pid(pid_t pid) -{ - return (kill(pid,0)==0) ? pid : -pid; -} - -// look for a process with a given name -// process: the name of the wanted process. it can be an absolute path name to the executable file -// or just the file name -// return: pid of the found process, if it is found -// 0, if it's not found -// negative pid, if it is found but it's not possible to control it -int look_for_process_by_name(const char *process_name) -{ - //whether the variable process_name is the absolute path or not - int is_absolute_path = process_name[0] == '/'; - //flag indicating if the a process with given name was found - int found = 0; - - //process iterator - struct process_iterator iter; - init_process_iterator(&iter); - pid_t pid = 0; - - while (read_next_process(&iter)==0) { - pid = iter.current->pid; - - int size = strlen(iter.current->command); - - found = 0; - if (is_absolute_path && strncmp(iter.current->command, process_name, size)==0 && size==strlen(process_name)) { - //process found - found = 1; - } - else { - //process found - if (strncmp(iter.current->command + size - strlen(process_name), process_name, strlen(process_name))==0) { - found = 1; - } - } - if (found==1) { - if (kill(pid,SIGCONT)==0) { - //process is ok! - break; - } - else { - //we don't have permission to send signal to that process - //so, don't exit from the loop and look for another one with the same name - found = -1; - } - } - } - if (close_process_iterator(&iter) != 1) exit(1); - if (found == 1) { - //ok, the process was found - return pid; - } - else if (found == 0) { - //no process found - return 0; - } - else if (found == -1) { - //the process was found, but we haven't permission to control it - return -pid; - } - //this MUST NOT happen - exit(2); -} - diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 487d7ea..61c342c 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,7 @@ void test_all_processes() struct process process; struct process_filter filter; filter.pid = 0; + filter.include_children = 0; init_process_iterator(&it, &filter); int count = 0; // time_t now = time(NULL); @@ -159,12 +161,29 @@ void test_process_group_single(int include_children) interval.tv_nsec = 50000000; nanosleep(&interval, NULL); } - assert(tot_usage / i < 1.1 && tot_usage / i > 0.9); + assert(tot_usage / i < 1.1 && tot_usage / i > 0.8); assert(close_process_group(&pgroup) == 0); kill(child, SIGINT); } -int main() +void test_process_name(const char * command) +{ + struct process_iterator it; + struct process process; + struct process_filter filter; + filter.pid = getpid(); + filter.include_children = 0; + init_process_iterator(&it, &filter); + assert(get_next_process(&it, &process) == 0); + assert(process.pid == getpid()); + assert(process.ppid == getppid()); +// printf("%s should be %s\n", command, process.command); + assert(strncmp(command, process.command, strlen(process.command)) == 0); + assert(get_next_process(&it, &process) != 0); + close_process_iterator(&it); +} + +int main(int argc, char **argv) { // printf("Pid %d\n", getpid()); test_single_process(); @@ -173,5 +192,6 @@ int main() test_process_group_all(); test_process_group_single(0); test_process_group_single(1); + test_process_name(argv[0]); return 0; } -- cgit v1.2.3 From b8bc055ee5131c333af3422569bde24bb760ac65 Mon Sep 17 00:00:00 2001 From: Angelo Marletta Date: Sat, 23 Jun 2012 12:57:42 +0100 Subject: full command line is detected on freebsd. deleted old files. all tests pass on linux and freebsd --- src/process.c | 265 ----------------------------------------- src/process.h | 88 -------------- src/process_iterator.h | 1 + src/process_iterator_freebsd.c | 54 +++++---- tests/process_iterator_test.c | 1 - 5 files changed, 29 insertions(+), 380 deletions(-) delete mode 100644 src/process.c delete mode 100644 src/process.h diff --git a/src/process.c b/src/process.c deleted file mode 100644 index 53226a7..0000000 --- a/src/process.c +++ /dev/null @@ -1,265 +0,0 @@ -/** - * - * cpulimit - a cpu limiter for Linux - * - * Copyright (C) 2005-2008, by: Angelo Marletta - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -//TODO: add documentation to public functions - -#include -#include -#include -#include -#include -#include -#include - -#include "process.h" - -#ifdef __APPLE__ -#include -#include -#endif - -#ifdef __FreeBSD__ -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef __linux__ -int get_proc_info(struct process *p, pid_t pid) { -/* static char statfile[20]; - static char buffer[64]; - int ret; - sprintf(statfile, "/proc/%d/stat", pid); - FILE *fd = fopen(statfile, "r"); - if (fd==NULL) return -1; - fgets(buffer, sizeof(buffer), fd); - fclose(fd); - - char state; - - int n = sscanf(buffer, "%d %s %c %d %d %d %d %d " - "%lu %lu %lu %lu %lu %lu %lu " - "%ld %ld %ld %ld %ld %ld " - "%lu ", - &p->pid, - &p->command, - &state, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - &utime,&stime,&cutime,&cstime, - NULL,NULL,NULL,NULL, - &starttime, - );*/ - return 0; -} -#elif defined __APPLE__ -int get_proc_info(struct process *p, pid_t pid) { - int err; - struct kinfo_proc *result = NULL; - size_t length; - int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - - /* We start by calling sysctl with result == NULL and length == 0. - That will succeed, and set length to the appropriate length. - We then allocate a buffer of that size and call sysctl again - with that buffer. - */ - length = 0; - err = sysctl(mib, 4, NULL, &length, NULL, 0); - if (err == -1) { - err = errno; - } - if (err == 0) { - result = malloc(length); - err = sysctl(mib, 4, result, &length, NULL, 0); - if (err == -1) - err = errno; - if (err == ENOMEM) { - free(result); /* clean up */ - result = NULL; - } - } - - p->pid = result->kp_proc.p_pid; - p->ppid = result->kp_eproc.e_ppid; - p->starttime = result->kp_proc.p_starttime.tv_sec; - p->last_jiffies = result->kp_proc.p_cpticks; - //p_pctcpu - - return 0; -} -#endif - -// returns the start time of a process (used with pid to identify a process) -static int get_starttime(pid_t pid) -{ -#ifdef __linux__ - char file[20]; - char buffer[1024]; - sprintf(file, "/proc/%d/stat", pid); - FILE *fd = fopen(file, "r"); - if (fd==NULL) return -1; - if (fgets(buffer, sizeof(buffer), fd) == NULL) return -1; - fclose(fd); - char *p = buffer; - p = memchr(p+1,')', sizeof(buffer) - (p-buffer)); - int sp = 20; - while (sp--) - p = memchr(p+1,' ',sizeof(buffer) - (p-buffer)); - //start time of the process - int time = atoi(p+1); - return time; -#elif defined __APPLE__ - struct process proc; - get_proc_info(&proc, pid); - return proc.starttime; -#elif defined __FreeBSD__ - return -1; -#endif -} - -static int get_jiffies(struct process *proc) { -#ifdef __linux__ - FILE *f = fopen(proc->stat_file, "r"); - if (f==NULL) return -1; - if (fgets(proc->buffer, sizeof(proc->buffer),f) == NULL) return -1; - fclose(f); - char *p = proc->buffer; - p = memchr(p+1,')', sizeof(proc->buffer) - (p-proc->buffer)); - int sp = 12; - while (sp--) - p = memchr(p+1,' ',sizeof(proc->buffer) - (p-proc->buffer)); - //user mode jiffies - int utime = atoi(p+1); - p = memchr(p+1,' ',sizeof(proc->buffer) - (p-proc->buffer)); - //kernel mode jiffies - int ktime = atoi(p+1); - return utime+ktime; -#elif defined __APPLE__ - struct process proc2; - get_proc_info(&proc2, proc->pid); - return proc2.last_jiffies; -#elif defined __FreeBSD__ - kvm_t *my_kernel = NULL; - struct kinfo_proc *process_data = NULL; - int processes; - int my_jiffies = -1; - my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open"); - if (! my_kernel) - { - printf("Error opening kernel vm. You should be running as root.\n"); - return -1; - } - - process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, proc->pid, &processes); - if ( (process_data) && (processes >= 1) ) - my_jiffies = process_data->ki_runtime; - - kvm_close(my_kernel); - if (my_jiffies >= 0) - my_jiffies /= 1000; - return my_jiffies; -#endif -} - -//return t1-t2 in microseconds (no overflow checks, so better watch out!) -static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2) -{ - return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec); -} - -/*static int*/ int process_update(struct process *proc) { - //TODO: get any process statistic here - //check that starttime is not changed(?), update jiffies, parent, zombie status - return 0; -} - -int process_init(struct process *proc, int pid) -{ - //general members - proc->pid = pid; - proc->starttime = get_starttime(pid); - proc->cpu_usage = 0; - memset(&(proc->last_sample), 0, sizeof(struct timeval)); - proc->last_jiffies = -1; - //system dependent members -#ifdef __linux__ -//TODO: delete these members for the sake of portability? - //test /proc file descriptor for reading - sprintf(proc->stat_file, "/proc/%d/stat", pid); - FILE *fd = fopen(proc->stat_file, "r"); - if (fd == NULL) return 1; - fclose(fd); -#endif - return 0; -} - -//parameter in range 0-1 -#define ALFA 0.08 - -int process_monitor(struct process *proc) -{ - int j = get_jiffies(proc); - if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead) - struct timeval now; - gettimeofday(&now, NULL); - if (proc->last_jiffies==-1) { - //store current time - proc->last_sample = now; - //store current jiffies - proc->last_jiffies = j; - //it's the first sample, cannot figure out the cpu usage - proc->cpu_usage = -1; - return 0; - } - //time from previous sample (in ns) - long dt = timediff(&now, &(proc->last_sample)); - //how many jiffies in dt? - double max_jiffies = dt * HZ / 1000000.0; - double sample = (j - proc->last_jiffies) / max_jiffies; - if (proc->cpu_usage == -1) { - //initialization - proc->cpu_usage = sample; - } - else { - //usage adjustment - proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample; - } - - //store current time - proc->last_sample = now; - //store current jiffies - proc->last_jiffies = j; - - return 0; -} - -int process_close(struct process *proc) -{ - if (kill(proc->pid,SIGCONT)!=0) { - fprintf(stderr,"Process %d is already dead!\n", proc->pid); - } - proc->pid = 0; - return 0; -} diff --git a/src/process.h b/src/process.h deleted file mode 100644 index 0280ad6..0000000 --- a/src/process.h +++ /dev/null @@ -1,88 +0,0 @@ -/** - * - * cpulimit - a cpu limiter for Linux - * - * Copyright (C) 2005-2008, by: Angelo Marletta - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __PROCESS_H - -#define __PROCESS_H - -#include -#include -#include - -//USER_HZ detection, from openssl code -#ifndef HZ -# if defined(_SC_CLK_TCK) \ - && (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000) -# define HZ ((double)sysconf(_SC_CLK_TCK)) -# else -# ifndef CLK_TCK -# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */ -# define HZ 100.0 -# else /* _BSD_CLK_TCK_ */ -# define HZ ((double)_BSD_CLK_TCK_) -# endif -# else /* CLK_TCK */ -# define HZ ((double)CLK_TCK) -# endif -# endif -#endif - -// process descriptor -struct process { - //pid of the process - pid_t pid; - //pid of the process - pid_t ppid; - //start time - int starttime; - //is member of the family? - int member; //TODO: delete this field - //total number of jiffies used by the process at time last_sample - int last_jiffies; - //timestamp when last_jiffies and cpu_usage was calculated - struct timeval last_sample; - //actual cpu usage estimation (value in range 0-1) - double cpu_usage; - //1 if the process is zombie - int is_zombie; - //absolute path of the executable file - char command[PATH_MAX+1]; - - //system-dependent members -//TODO: delete these members for the sake of portability? -#ifdef __linux__ - //preallocate buffers for performance - //name of /proc/PID/stat file - char stat_file[20]; - //read buffer for /proc filesystem - char buffer[1024]; -#endif -}; - -int get_proc_info(struct process *p, pid_t pid); - -int process_init(struct process *proc, pid_t pid); - -int process_monitor(struct process *proc); - -int process_close(struct process *proc); - -#endif diff --git a/src/process_iterator.h b/src/process_iterator.h index 39379b8..82fadac 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -76,6 +76,7 @@ struct process_iterator { DIR *dip; int boot_time; #elif defined __FreeBSD__ + kvm_t *kd; struct kinfo_proc *procs; int count; int i; diff --git a/src/process_iterator_freebsd.c b/src/process_iterator_freebsd.c index e840968..eb6cfaa 100644 --- a/src/process_iterator_freebsd.c +++ b/src/process_iterator_freebsd.c @@ -4,55 +4,46 @@ #include int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { - kvm_t *kd; char errbuf[_POSIX2_LINE_MAX]; it->i = 0; /* Open the kvm interface, get a descriptor */ - if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { - /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: %s", errbuf); + if ((it->kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { + fprintf(stderr, "kvm_open: %s\n", errbuf); return -1; } /* Get the list of processes. */ - if ((it->procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { - kvm_close(kd); - /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */ - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); + if ((it->procs = kvm_getprocs(it->kd, KERN_PROC_PROC, 0, &it->count)) == NULL) { + kvm_close(it->kd); + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd)); return -1; } - kvm_close(kd); it->filter = filter; return 0; } -static void kproc2proc(struct kinfo_proc *kproc, struct process *proc) +static void kproc2proc(kvm_t *kd, struct kinfo_proc *kproc, struct process *proc) { proc->pid = kproc->ki_pid; proc->ppid = kproc->ki_ppid; proc->cputime = kproc->ki_runtime / 1000; proc->starttime = kproc->ki_start.tv_sec; - memcpy(proc->command, kproc->ki_comm, strlen(kproc->ki_comm)); + char **args = kvm_getargv(kd, kproc, sizeof(proc->command)); + if (args != NULL) + { + memcpy(proc->command, args[0], strlen(args[0]) + 1); + } } -static int get_single_process(pid_t pid, struct process *process) +static int get_single_process(kvm_t *kd, pid_t pid, struct process *process) { - kvm_t *kd; int count; - char errbuf[_POSIX2_LINE_MAX]; - /* Open the kvm interface, get a descriptor */ - if ((kd = kvm_openfiles(NULL, _PATH_DEVNULL, NULL, O_RDONLY, errbuf)) == NULL) { - /* fprintf(stderr, "kvm_open: %s\n", errbuf); */ - fprintf(stderr, "kvm_open: %s", errbuf); - return -1; - } struct kinfo_proc *kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &count); - kvm_close(kd); if (count == 0 || kproc == NULL) { - fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd)); + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); return -1; } - kproc2proc(kproc, process); + kproc2proc(kd, kproc, process); return 0; } @@ -63,15 +54,22 @@ int get_next_process(struct process_iterator *it, struct process *p) { } if (it->filter->pid > 0 && !it->filter->include_children) { - get_single_process(it->filter->pid, p); + get_single_process(it->kd, it->filter->pid, p); it->i = it->count = 1; return 0; } while (it->i < it->count) { + struct kinfo_proc *kproc = &(it->procs[it->i]); + if (kproc->ki_flag & P_SYSTEM) + { + // skip system processes + it->i++; + continue; + } if (it->filter->pid > 0 && it->filter->include_children) { - kproc2proc(&(it->procs[it->i]), p); + kproc2proc(it->kd, kproc, p); it->i++; if (p->pid != it->filter->pid && p->ppid != it->filter->pid) continue; @@ -79,7 +77,7 @@ int get_next_process(struct process_iterator *it, struct process *p) { } else if (it->filter->pid == 0) { - kproc2proc(&(it->procs[it->i]), p); + kproc2proc(it->kd, kproc, p); it->i++; return 0; } @@ -88,6 +86,10 @@ int get_next_process(struct process_iterator *it, struct process *p) { } int close_process_iterator(struct process_iterator *it) { + if (kvm_close(it->kd) == -1) { + fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(it->kd)); + return -1; + } return 0; } diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 61c342c..f5b7586 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -177,7 +177,6 @@ void test_process_name(const char * command) assert(get_next_process(&it, &process) == 0); assert(process.pid == getpid()); assert(process.ppid == getppid()); -// printf("%s should be %s\n", command, process.command); assert(strncmp(command, process.command, strlen(process.command)) == 0); assert(get_next_process(&it, &process) != 0); close_process_iterator(&it); -- cgit v1.2.3