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 ----------------------------------------- 7 files changed, 157 insertions(+), 592 deletions(-) delete mode 100644 src/procutils.c (limited to 'src') 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); -} - -- cgit v1.2.3