Load cpulimit/ into cpulimit/branches/upstream/current. upstream/1.2_svn14
authorgregor herrmann <gregoa@debian.org>
Thu, 28 Aug 2008 17:57:25 +0000 (17:57 -0000)
committergregor herrmann <gregoa@debian.org>
Thu, 28 Aug 2008 17:57:25 +0000 (17:57 -0000)
Makefile
cpulimit.c
list.c
process.c
process.h
procutils.c
procutils.h
ptest.c

index 261a76a..7bd54ec 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,6 @@ all::   $(TARGETS)
 cpulimit:      cpulimit.c $(LIBS)
        $(CC) -o cpulimit cpulimit.c $(LIBS) -lrt $(CFLAGS)
 
-ptest: ptest.c process.o procutils.o list.o
-       $(CC) -o ptest ptest.c process.o procutils.o list.o -lrt $(CFLAGS)
-
 process.o: process.c process.h
        $(CC) -c process.c $(CFLAGS)
 
@@ -20,6 +17,9 @@ procutils.o: procutils.c procutils.h
 list.o: list.c list.h
        $(CC) -c list.c $(CFLAGS)
 
+ptest: ptest.c
+       $(CC) -o ptest ptest.c -lrt $(CFLAGS)
+
 clean:
        rm -f *~ *.o $(TARGETS)
 
index bf912d6..eb796cd 100644 (file)
 #define MIN(a,b) (a<b?a:b)
 #define MAX(a,b) (a>b?a:b)
 #define print_caption()        printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n")
+
 //control time slot in microseconds
 //each slot is splitted in a working slice and a sleeping slice
-#define CONTROL_SLOT 100000
+#define TIME_SLOT 100000
 
 #define MAX_PRIORITY -10
 
+/* GLOBAL VARIABLES */
+
 //the "family"
 struct process_family pf;
 //pid of cpulimit
@@ -143,7 +146,7 @@ void print_usage(FILE *stream, int exit_code)
        exit(exit_code);
 }
 
-void limit_process(int pid, float limit)
+void limit_process(int pid, double limit)
 {
        //slice of the slot in which the process is allowed to run
        struct timespec twork;
@@ -168,20 +171,24 @@ void limit_process(int pid, float limit)
        
        if (verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.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 (i%100==0 && verbose) print_caption();
+               if (i%200==0 && verbose) print_caption();
 
                if (i%10==0) {
                        //update the process family (checks only for new members)
-                       int newborn = check_new_members(&pf);
-                       if (newborn) {
-                               printf("%d new children processes detected (", newborn);
+                       int new_children = update_process_family(&pf);
+                       if (new_children) {
+                               printf("%d new children processes detected (", new_children);
                                int j;
                                node = pf.members.last;
-                               for (j=0; j<newborn; j++) {
+                               for (j=0; j<new_children; j++) {
                                        printf("%d", ((struct process*)(node->data))->pid);
-                                       if (j<newborn-1) printf(" ");
+                                       if (j<new_children-1) printf(" ");
                                        node = node->previous;
                                }
                                printf(")\n");
@@ -190,44 +197,46 @@ void limit_process(int pid, float limit)
 
                //total cpu actual usage (range 0-1)
                //1 means that the processes are using 100% cpu
-               float pcpu = 0;
-               //rate at which we are keeping active the processes (range 0-1)
-               //1 means that the process are using all the twork slice
-               float workingrate = 0;
-
+               double pcpu = -1;
+               //number of processes in the family
+               int pcount = 0;
+               
                //estimate how much the controlled processes are using the cpu in the working interval
                for (node=pf.members.first; node!=NULL; node=node->next) {
                        struct process *proc = (struct process*)(node->data);
-                       if (process_monitor(proc->history, workingtime, &(proc->history->usage))==-1) {
+                       if (process_monitor(proc->history)==-1) {
                                //process is dead, remove it from family
-                               remove_process_from_family(&pf, proc->pid);
                                fprintf(stderr,"Process %d dead!\n", proc->pid);
+                               remove_process_from_family(&pf, proc->pid);
+                               continue;
+                       }
+//printf("pid %d limit %f pcpu %f wrate %f\n", proc->pid, limit, proc->history->usage.pcpu, proc->history->usage.workingrate);
+                       if (proc->history->cpu_usage<0) {
+                               continue;
                        }
-                       pcpu += proc->history->usage.pcpu;
-                       workingrate += proc->history->usage.workingrate;
+                       if (pcpu<0) pcpu = 0;
+                       pcpu += proc->history->cpu_usage;
+                       pcount++;
                }
-               //average value
-               workingrate /= pf.members.count;
-
-               //TODO: make workingtime customized for each process, now it's equal for all
 
                //adjust work and sleep time slices
-               if (pcpu>0) {
-                       twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000/pcpu*workingrate,CONTROL_SLOT*1000);
-               }
-               else if (pcpu==0) {
-                       twork.tv_nsec = CONTROL_SLOT*1000;
-               }
-               else if (pcpu==-1) {
-                       //not yet a valid idea of cpu usage
+               if (pcpu < 0) {
+                       //it's the 1st cycle, initialize workingrate
                        pcpu = limit;
                        workingrate = limit;
-                       twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000,CONTROL_SLOT*1000);
+                       twork.tv_nsec = TIME_SLOT*limit*1000;
                }
-               tsleep.tv_nsec = CONTROL_SLOT*1000-twork.tv_nsec;
+               else {
+                       //adjust workingrate
+                       workingrate = MIN(workingrate / pcpu * limit, 1);
+                       twork.tv_nsec = TIME_SLOT*1000*workingrate;
+               }
+               tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec;
+
+//printf("%lf %lf\n", workingrate, pcpu);
 
                if (verbose && i%10==0 && i>0) {
-                       printf("%0.2f%%\t%6ld us\t%6ld us\t%0.2f%%\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
@@ -246,25 +255,25 @@ void limit_process(int pid, float limit)
                clock_gettime(CLOCK_REALTIME,&endwork);
                workingtime = timediff(&endwork,&startwork);
 
-               //stop processes, they have worked enough
-               //resume processes
-               for (node=pf.members.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
-                               fprintf(stderr,"Process %d dead!\n", proc->pid);
-                               remove_process_from_family(&pf, proc->pid);
+               if (tsleep.tv_nsec>0) {
+                       //stop only if tsleep>0, instead it's useless
+                       for (node=pf.members.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
+                                       fprintf(stderr,"Process %d dead!\n", proc->pid);
+                                       remove_process_from_family(&pf, proc->pid);
+                               }
                        }
+                       //now the processes are sleeping
+                       nanosleep(&tsleep,NULL);
                }
-               //now the process is forced to sleep
-               nanosleep(&tsleep,NULL);
                i++;
        }
        cleanup_process_family(&pf);
 }
 
 int main(int argc, char **argv) {
-
        //get program name
        char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
        program_name = p==NULL?argv[0]:(p+1);
@@ -334,13 +343,19 @@ int main(int argc, char **argv) {
                lazy = 1;
        }
        
+       if (pid_ok && (pid<=1 || pid>=65536)) {
+               fprintf(stderr,"Error: Invalid value for argument PID\n");
+               print_usage(stderr, 1);
+               exit(1);
+       }
+       
        if (!process_ok) {
-               fprintf(stderr,"Error: You must specify a target process, by name or by PID\n");
+               fprintf(stderr,"Error: You must specify a target process, either by name or by PID\n");
                print_usage(stderr, 1);
                exit(1);
        }
        if (pid_ok && exe!=NULL) {
-               fprintf(stderr, "Error: You must specify exactly one process, by name or by PID\n");
+               fprintf(stderr, "Error: You must specify exactly one process, either by name or by PID\n");
                print_usage(stderr, 1);
                exit(1);
        }
@@ -349,8 +364,9 @@ int main(int argc, char **argv) {
                print_usage(stderr, 1);
                exit(1);
        }
-       float limit = perclimit/100.0;
+       double limit = perclimit/100.0;
        int cpu_count = get_cpu_count();
+       printf("%d cpu detected\n", cpu_count);
        if (limit<0 || limit >cpu_count) {
                fprintf(stderr,"Error: limit must be in the range 0-%d00\n", cpu_count);
                print_usage(stderr, 1);
@@ -370,7 +386,7 @@ int main(int argc, char **argv) {
                printf("Priority changed to %d\n", priority);
        }
        else {
-               printf("Cannot change priority\n");
+               printf("Warning: Cannot change priority. Run as root for best results.\n");
        }
        
        while(1) {
diff --git a/list.c b/list.c
index 6ec1fd4..193eac9 100644 (file)
--- a/list.c
+++ b/list.c
 /**
- *
- * cpulimit - a cpu limiter for Linux
- *
- * Copyright (C) 2005-2008, by:  Angelo Marletta <marlonx80@hotmail.com>
- *
- * 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.
- *
- **********************************************************************
- *
- * Dynamic list implementation
- *
- */
+*
+* cpulimit - a cpu limiter for Linux
+*
+* Copyright (C) 2005-2008, by:  Angelo Marletta <marlonx80@hotmail.com>
+*
+* 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.
+*
+**********************************************************************
+*
+* Dynamic list implementation
+*
+*/
 
 #include "list.h"
 
 #define EMPTYLIST NULL
 
 void init_list(struct list *l,int keysize) {
-    l->first=l->last=NULL;
-    l->keysize=keysize;
-    l->count=0;
+       l->first=l->last=NULL;
+       l->keysize=keysize;
+       l->count=0;
 }
 
 struct list_node *add_elem(struct list *l,void *elem) {
-    struct list_node *newnode=malloc(sizeof(struct list_node));
-    newnode->data=elem;
-    newnode->previous=l->last;
-    newnode->next=NULL;
-    if (l->count==0) {
-        l->first=l->last=newnode;
-    }
-    else {
-        l->last->next=newnode;
-        l->last=newnode;
-    }
-    l->count++;
-    return newnode;
+       struct list_node *newnode=malloc(sizeof(struct list_node));
+       newnode->data=elem;
+       newnode->previous=l->last;
+       newnode->next=NULL;
+       if (l->count==0) {
+               l->first=l->last=newnode;
+       }
+       else {
+               l->last->next=newnode;
+               l->last=newnode;
+       }
+       l->count++;
+       return newnode;
 }
 
 void delete_node(struct list *l,struct list_node *node) {
-    if (l->count==1) l->first=l->last=NULL;
-    else
-        if (node==l->first) {
-        node->next->previous=NULL;
-        l->first=node->next;
-    }
-    else
-        if (node==l->last) {
-            node->previous->next=NULL;
-            l->last=node->previous;
-        }
-        else {
-            node->previous->next=node->next;
-            node->next->previous=node->previous;
-        }
-    l->count--;
-    free(node);
+       if (l->count==1) {
+               l->first=l->last=NULL;
+       }
+       else if (node==l->first) {
+               node->next->previous=NULL;
+               l->first=node->next;
+       }
+       else if (node==l->last) {
+               node->previous->next=NULL;
+               l->last=node->previous;
+       }
+       else {
+               node->previous->next=node->next;
+               node->next->previous=node->previous;
+       }
+       l->count--;
+       free(node);
+       node = NULL;
 }
 
 void destroy_node(struct list *l,struct list_node *node) {
-    free(node->data);
-    node->data=NULL;
-    delete_node(l,node);
+       free(node->data);
+       node->data=NULL;
+       delete_node(l,node);
 }
 
 int is_EMPTYLIST_list(struct list *l) {
-    return (l->count==0?TRUE:FALSE);
+       return (l->count==0?TRUE:FALSE);
 }
 
 int get_list_count(struct list *l) {
-    return l->count;
+       return l->count;
 }
 
 void *first_elem(struct list *l) {
-    return l->first->data;
+       return l->first->data;
 }
 
 struct list_node *first_node(struct list *l) {
-    return l->first;
+       return l->first;
 }
 
 void *last_elem(struct list *l) {
-    return l->last->data;
+       return l->last->data;
 }
 
 struct list_node *last_node(struct list *l) {
-    return l->last;
+       return l->last;
 }
 
 struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) {
-    struct list_node *tmp;
-    tmp=l->first;
-    while(tmp!=NULL) {
-        if(!memcmp(tmp->data+offset,elem,length==0?l->keysize:length)) return (tmp);
-        tmp=tmp->next;
-    }
-    return EMPTYLIST;
+       struct list_node *tmp;
+       tmp=l->first;
+       while(tmp!=NULL) {
+               if(!memcmp(tmp->data+offset,elem,length==0?l->keysize:length)) return (tmp);
+               tmp=tmp->next;
+       }
+       return EMPTYLIST;
 }
 
 struct list_node *locate_node(struct list *l,void *elem) {
-    return(xlocate_node(l,elem,0,0));
+       return(xlocate_node(l,elem,0,0));
 }
 
 void *xlocate_elem(struct list *l,void *elem,int offset,int length) {
-    struct list_node *node=xlocate_node(l,elem,offset,length);
-    return(node==NULL?NULL:node->data);
+       struct list_node *node=xlocate_node(l,elem,offset,length);
+       return(node==NULL?NULL:node->data);
 }
 
 void *locate_elem(struct list *l,void *elem) {
-    return(xlocate_elem(l,elem,0,0));
+       return(xlocate_elem(l,elem,0,0));
 }
 
 void flush_list(struct list *l) {
-    struct list_node *tmp;
-    while(l->first!=EMPTYLIST) {
-        tmp=l->first;
-        l->first=l->first->next;
-        free(tmp);
-        tmp=NULL;
-    }
-    l->last=EMPTYLIST;
-    l->count=0;
+       struct list_node *tmp;
+       while(l->first!=EMPTYLIST) {
+               tmp=l->first;
+               l->first=l->first->next;
+               free(tmp);
+               tmp=NULL;
+       }
+       l->last=EMPTYLIST;
+       l->count=0;
 }
 
 void destroy_list(struct list *l) {
-    struct list_node *tmp;
-    while(l->first!=EMPTYLIST) {
-        tmp=l->first;
-        l->first=l->first->next;
-        free(tmp->data);
-        tmp->data=NULL;
-        free(tmp);
-        tmp=NULL;
-    }
-    l->last=EMPTYLIST;
-    l->count=0;
+       struct list_node *tmp;
+       while(l->first!=EMPTYLIST) {
+               tmp=l->first;
+               l->first=l->first->next;
+               free(tmp->data);
+               tmp->data=NULL;
+               free(tmp);
+               tmp=NULL;
+       }
+       l->last=EMPTYLIST;
+       l->count=0;
 }
index e044fdc..4131ce4 100644 (file)
--- a/process.c
+++ b/process.c
 
 int process_init(struct process_history *proc, int pid)
 {
-       proc->pid = pid;
-       //init circular queue
-       proc->front_index = -1;
-       proc->tail_index = 0;
-       proc->actual_history_size = 0;
-       memset(proc->history, 0, sizeof(proc->history));
-       proc->total_workingtime = 0;
        //test /proc file descriptor for reading
-       sprintf(proc->stat_file, "/proc/%d/stat", proc->pid);
+       sprintf(proc->stat_file, "/proc/%d/stat", pid);
        FILE *fd = fopen(proc->stat_file, "r");
+       if (fd == NULL) return 1;
        fclose(fd);
-       proc->usage.pcpu = 0;
-       proc->usage.workingrate = 0;
-       return (fd == NULL);
+       //init properties
+       proc->pid = pid;
+       proc->cpu_usage = 0;
+       memset(&(proc->last_sample), 0, sizeof(struct timespec));
+       proc->last_jiffies = -1;
+       return 0;
 }
 
 //return t1-t2 in microseconds (no overflow checks, so better watch out!)
@@ -65,46 +62,43 @@ static int get_jiffies(struct process_history *proc) {
        return utime+ktime;
 }
 
-int process_monitor(struct process_history *proc, int last_working_quantum, struct cpu_usage *usage)
-{
-       //increment front index
-       proc->front_index = (proc->front_index+1) % HISTORY_SIZE;
-
-       //actual history size is: (front-tail+HISTORY_SIZE)%HISTORY_SIZE+1
-       proc->actual_history_size = (proc->front_index - proc->tail_index + HISTORY_SIZE) % HISTORY_SIZE + 1;
-
-       //actual front and tail of the queue
-       struct process_screenshot *front = &(proc->history[proc->front_index]);
-       struct process_screenshot *tail = &(proc->history[proc->tail_index]);
+#define ALFA 0.08
 
-       //take a shot and save in front
+int process_monitor(struct process_history *proc)
+{
        int j = get_jiffies(proc);
        if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead)
-       front->jiffies = j;
-       clock_gettime(CLOCK_REALTIME, &(front->when));
-       front->cputime = last_working_quantum;
-
-       if (proc->actual_history_size==1) {
-               //not enough elements taken (it's the first one!), return 0
-               usage->pcpu = -1;
-               usage->workingrate = 1;
+       struct timespec now;
+       clock_gettime(CLOCK_REALTIME, &now);
+       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 {
-               //queue has enough elements
-               //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
-               long dt = timediff(&(front->when), &(tail->when));
-               //the total time between tail and front in which the process was allowed to run
-               proc->total_workingtime += front->cputime - tail->cputime;
-               int used_jiffies = front->jiffies - tail->jiffies;
-               float usage_ratio = (used_jiffies*1000000.0/HZ) / proc->total_workingtime;
-               usage->workingrate = 1.0 * proc->total_workingtime / dt;
-               usage->pcpu = usage_ratio * usage->workingrate;
-               //increment tail index if the queue is full
-               if (proc->actual_history_size==HISTORY_SIZE)
-                       proc->tail_index = (proc->tail_index+1) % HISTORY_SIZE;
-               return 0;
+               //adaptative 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_history *proc)
index 16cbf8f..5a73cc2 100644 (file)
--- a/process.h
+++ b/process.h
 #include <sys/time.h>
 #include <unistd.h>
 
-//kernel time resolution (inverse of one jiffy interval) in Hertz
+//kernel time resolution timer interrupt frequency in Hertz
 #define HZ sysconf(_SC_CLK_TCK)
-//size of the history circular queue
-#define HISTORY_SIZE 10
-
-//extracted process statistics
-struct cpu_usage {
-       float pcpu;
-       float workingrate;
-};
-
-//process instant photo
-struct process_screenshot {
-       //timestamp
-       struct timespec when;
-       //total jiffies used by the process
-       int jiffies;
-       //cpu time used since previous screenshot expressed in microseconds
-       int cputime;
-};
 
 //process descriptor
 struct process_history {
@@ -61,23 +43,17 @@ struct process_history {
        char stat_file[20];
        //read buffer for /proc filesystem
        char buffer[1024];
-       //recent history of the process (fixed circular queue)
-       struct process_screenshot history[HISTORY_SIZE];
-       //the index of the last screenshot made to the process
-       int front_index;
-       //the index of the oldest screenshot made to the process
-       int tail_index;
-       //how many screenshots we have in the queue (max HISTORY_SIZE)
-       int actual_history_size;
-       //total cputime saved in the history
-       long total_workingtime;
-       //current usage
-       struct cpu_usage usage;
+       //timestamp when last_j and cpu_usage was calculated
+       struct timespec last_sample;
+       //total number of jiffies used by the process at time last_sample
+       int last_jiffies;
+       //cpu usage estimation (value in range 0-1)
+       double cpu_usage;
 };
 
 int process_init(struct process_history *proc, int pid);
 
-int process_monitor(struct process_history *proc, int last_working_quantum, struct cpu_usage *usage);
+int process_monitor(struct process_history *proc);
 
 int process_close(struct process_history *proc);
 
index c203daf..989c555 100644 (file)
@@ -112,8 +112,11 @@ static int hash_process(struct process_family *f, struct process *p)
                //list already exists
                struct process *tmp = (struct process*)locate_elem(*l, p);
                if (tmp != NULL) {
+                       //TODO: should free() something? tmp? p?
                        //update process info
                        memcpy(tmp, p, sizeof(struct process));
+                       free(p);
+                       p = NULL;
                        ret = 1;
                }
                else {
@@ -137,7 +140,7 @@ static void unhash_process(struct process_family *f, int pid) {
        f->count--;
 }
 
-static struct process *find_process(struct process_family *f, int pid)
+static struct process *seek_process(struct process_family *f, int pid)
 {
        struct list **l = &(f->hashtable[pid_hashfn(pid)]);
        return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
@@ -145,12 +148,12 @@ static struct process *find_process(struct process_family *f, int pid)
 
 /*
 static int is_member(struct process_family *f, int pid) {
-       struct process *p = find_process(f, pid);
+       struct process *p = seek_process(f, pid);
        return (p!=NULL && p->member);
 }
 
 static int exists(struct process_family *f, int pid) {
-       struct process *p = find_process(f, pid);
+       struct process *p = seek_process(f, pid);
        return p!=NULL;
 }
 */
@@ -192,7 +195,7 @@ static int read_next_process(struct process_iterator *i) {
 // in the process family struct
 int create_process_family(struct process_family *f, int father)
 {
-       //process list initialization
+       //process list initialization (4 bytes key)
        init_list(&(f->members), 4);
        //hashtable initialization
        memset(&(f->hashtable), 0, sizeof(f->hashtable));
@@ -205,7 +208,7 @@ int create_process_family(struct process_family *f, int father)
        while ((pid = read_next_process(&iter))) {
                //check if process belongs to the family
                int ppid = pid;
-               //TODO: optimize (add also parents)
+               //TODO: optimize adding also these parents, and continue if process is already present
                while(ppid!=1 && ppid!=father) {
                        ppid = getppid_of(ppid);
                }
@@ -214,10 +217,11 @@ int create_process_family(struct process_family *f, int father)
                p->pid = pid;
                p->starttime = get_starttime(pid);
                if (ppid==1) {
+                       //the init process
                        p->member = 0;
                }
                else if (pid != getpid()) {
-                       //add to members (only if it's not the current cpulimit process!)
+                       //add to members (but exclude the current cpulimit process!)
                        p->member = 1;
                        add_elem(&(f->members), p);
                }
@@ -233,7 +237,7 @@ int create_process_family(struct process_family *f, int father)
 // 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 check_new_members(struct process_family *f)
+int update_process_family(struct process_family *f)
 {
        int ret = 0;
        //process iterator
@@ -241,31 +245,34 @@ int check_new_members(struct process_family *f)
        init_process_iterator(&iter);
        int pid = 0;
        while ((pid = read_next_process(&iter))) {
-               struct process *newp = find_process(f, pid);
-               if (newp != NULL) continue; //already known
+               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=find_process(f, ppid))==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
-                       printf("Fatal bug! Process %d is without parent\n", pid);
+                       fprintf(stderr, "Fatal bug! Process %d is without parent\n", pid);
                        exit(1);
                }
                //allocate and insert the process
                struct process *p = malloc(sizeof(struct process));
                p->pid = pid;
                p->starttime = get_starttime(pid);
-               p->member = 0;
                if (ancestor->member) {
                        //add to members
                        p->member = 1;
                        add_elem(&(f->members), p);
                        ret++;
                }
+               else {
+                       //not a member
+                       p->member = 0;
+               }
                //init history
                p->history = malloc(sizeof(struct process_history));
                process_init(p->history, pid);
@@ -283,7 +290,7 @@ void remove_process_from_family(struct process_family *f, int pid)
                struct process *p = (struct process*)(node->data);
                free(p->history);
                p->history = NULL;
-               destroy_node(&(f->members), node);
+               delete_node(&(f->members), node);
        }
        unhash_process(f, pid);
 }
index 87f0395..8a1deb2 100644 (file)
@@ -40,7 +40,8 @@
 struct process_family {
        //the (god)father of the process family
        int father;
-       //members list (father process is the first element)
+       //process list (father process is the first element)
+       //elements are struct process
        struct list members;
        //non-members list
        //hashtable with all the processes (array of struct list of struct process)
@@ -51,8 +52,11 @@ struct process_family {
 
 // process descriptor
 struct process {
+       //pid of the process
        int pid;
+       //start time
        int starttime;
+       //is member of the family?
        int member;
        struct process_history *history;
 };
@@ -70,7 +74,7 @@ int create_process_family(struct process_family *f, int father);
 // 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 check_new_members(struct process_family *f);
+int update_process_family(struct process_family *f);
 
 // removes a process from the family by its pid
 void remove_process_from_family(struct process_family *f, int pid);
diff --git a/ptest.c b/ptest.c
index 9fadb6f..64b124d 100644 (file)
--- a/ptest.c
+++ b/ptest.c
@@ -3,19 +3,56 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include "procutils.h"
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-//simple program to test cpulimit
+#define N 8
 
+//simple program to test cpulimit
 int main()
 {
-       printf("PID %d\n", getpid());
+       printf("Parent: PID %d\n", getpid());
+       getchar();
+       sleep(1);
        int i;
-       for (i=0;i<10;i++) {
-               if (fork()>0){
-                       printf("PID %d\n", getpid());
+       int children[N];
+       for (i=0;i<N;i++) {
+               int pid = fork();
+               if (pid>0) {
+                       //parent code
+                       children[i] = pid;
+                       printf("Child %d created\n", pid);
+               }
+               else if (pid==0) {
                        while(1);
+                       //child code
+//                     while(1) {
+                               //random generator initialization
+                               struct timeval t;
+                               gettimeofday(&t, NULL);
+                               srandom(t.tv_sec + t.tv_usec + getpid());
+                               int loop = random() % 1000000;
+                               printf("start\n");
+                               int i,j;
+                               for (i=0;i<1000;i++)
+                                       for (j=0;j<loop;j++);
+                               printf("stop\n");
+                               int time = random() % 10000000;
+       //                      printf("Child %d wait %d\n", getpid(), time);
+                               usleep(time);
+                               printf("Child %d terminated\n", getpid());
+//                     }
+                       exit(0);
+               }
+               else {
+                       fprintf(stderr, "fork() failed!\n");
                }
        }
+       for (i=0;i<N;i++) {
+               int status;
+               waitpid(children[i], &status, 0);
+       }
+       sleep(1);
        return 0;
 }