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 ++++++-- 5 files changed, 344 insertions(+), 64 deletions(-) create mode 100644 src/process_group.c create mode 100644 src/process_group.h (limited to 'src') 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); -- cgit v1.2.3