[svn-upgrade] Integrating new upstream version, cpulimit (1.12~svn10)
[debian/cpulimit.git] / cpulimit.c
index bd2ea0a..bf912d6 100644 (file)
@@ -1,36 +1,50 @@
 /**
- * Copyright (c) 2005, by:      Angelo Marletta <marlonx80@hotmail.com>
  *
- * This file may be used subject to the terms and conditions of the
- * GNU Library General Public License Version 2, or any later version
- * at your option, as published by the Free Software Foundation.
+ * 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 Library General Public License for more details.
+ * 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.
  *
  **********************************************************************
  *
- * Simple program to limit the cpu usage of a process
+ * This is a simple program to limit the cpu usage of a process
  * If you modify this code, send me a copy please
  *
- * Author:  Angelo Marletta
- * Date:    26/06/2005
- * Version: 1.1
- * Last version at: http://marlon80.interfree.it/cpulimit/index.html
+ * Date:    15/2/2008
+ * Version: 1.2 alpha
+ * Get the latest version at: http://cpulimit.sourceforge.net
  *
  * Changelog:
- *  - Fixed a segmentation fault if controlled process exited in particular circumstances
- *  - Better CPU usage estimate
- *  - Fixed a <0 %CPU usage reporting in rare cases
- *  - Replaced MAX_PATH_SIZE with PATH_MAX already defined in <limits.h>
- *  - Command line arguments now available
- *  - Now is possible to specify target process by pid
+ * - reorganization of the code, splitted in more source files
+ * - control function process_monitor() optimized by eliminating an unnecessary loop
+ * - experimental support for multiple control of children processes and threads
+ *   children detection algorithm seems heavy because of the amount of code,
+ *   but it's designed to be scalable when there are a lot of children processes
+ * - cpu count detection, i.e. if you have 4 cpu, it is possible to limit up to 400%
+ * - in order to avoid deadlock, cpulimit prevents to limit itself
+ * - option --path eliminated, use --exe instead both for absolute path and file name
+ * - deleted almost every setpriority(), just set it once at startup
+ * - minor enhancements and bugfixes
+ *
  */
 
 
 #include <getopt.h>
 #include <stdio.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <time.h>
 #include <sys/time.h>
 #include <errno.h>
 #include <string.h>
 
-//kernel time resolution (inverse of one jiffy interval) in Hertz
-//i don't know how to detect it, then define to the default (not very clean!)
-#define HZ 100
+#include "process.h"
+#include "procutils.h"
+#include "list.h"
 
 //some useful macro
-#define min(a,b) (a<b?a:b)
-#define max(a,b) (a>b?a:b)
-
-//pid of the controlled process
-int pid=0;
-//executable file name
+#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 MAX_PRIORITY -10
+
+//the "family"
+struct process_family pf;
+//pid of cpulimit
+int cpulimit_pid;
+//name of this program (maybe cpulimit...)
 char *program_name;
+
+/* CONFIGURATION VARIABLES */
+
 //verbose mode
-int verbose=0;
-//lazy mode
-int lazy=0;
+int verbose = 0;
+//lazy mode (exits if there is no process)
+int lazy = 0;
+
+//how many cpu do we have?
+int get_cpu_count()
+{
+       FILE *fd;
+       int cpu_count = 0;
+       char line[100];
+       fd = fopen("/proc/stat", "r");
+       if (fd < 0)
+               return 0; //are we running Linux??
+       while (fgets(line,sizeof(line),fd)!=NULL) {
+               if (strncmp(line, "cpu", 3) != 0) break;
+               cpu_count++;
+       }
+       fclose(fd);
+       return cpu_count - 1;
+}
 
-//reverse byte search
-void *memrchr(const void *s, int c, size_t n);
+//return t1-t2 in microseconds (no overflow checks, so better watch out!)
+inline unsigned long timediff(const struct timespec *t1,const struct timespec *t2)
+{
+       return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_nsec/1000 - t2->tv_nsec/1000);
+}
 
-//return ta-tb in microseconds (no overflow checks!)
-inline long timediff(const struct timespec *ta,const struct timespec *tb) {
-    unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
-    return us;
+//returns t1-t2 in microseconds
+inline unsigned long long tv_diff(struct timeval *t1, struct timeval *t2)
+{
+       return ((unsigned long long)(t1->tv_sec - t2->tv_sec)) * 1000000ULL + t1->tv_usec - t2->tv_usec;
 }
 
-int waitforpid(int pid) {
-       //switch to low priority
-       if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
-               printf("Warning: cannot renice\n");
+//SIGINT and SIGTERM signal handler
+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) {
+               struct process *p = (struct process*)(node->data);
+               process_close(p->history);
+               kill(p->pid, SIGCONT);
        }
+       //free all the memory
+       cleanup_process_family(&pf);
+       exit(0);
+}
 
-       int i=0;
-
-       while(1) {
+void print_usage(FILE *stream, int exit_code)
+{
+       fprintf(stream, "Usage: %s TARGET [OPTIONS...]\n",program_name);
+       fprintf(stream, "   TARGET must be exactly one of these:\n");
+       fprintf(stream, "      -p, --pid=N        pid of the process (implies -z)\n");
+       fprintf(stream, "      -e, --exe=FILE     name of the executable program file or absolute path name\n");
+       fprintf(stream, "   OPTIONS\n");
+       fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 0 to 100 (required)\n");
+       fprintf(stream, "      -v, --verbose      show control statistics\n");
+       fprintf(stream, "      -z, --lazy         exit if there is no suitable target process, or if it dies\n");
+       fprintf(stream, "      -h, --help         display this help and exit\n");
+       exit(exit_code);
+}
 
-               DIR *dip;
-               struct dirent *dit;
+void limit_process(int pid, float limit)
+{
+       //slice of the slot in which the process is allowed to run
+       struct timespec twork;
+       //slice of the slot in which the process is stopped
+       struct timespec tsleep;
+       //when the last twork has started
+       struct timespec startwork;
+       //when the last twork has finished
+       struct timespec endwork;
+       //initialization
+       memset(&twork, 0, sizeof(struct timespec));
+       memset(&tsleep, 0, sizeof(struct timespec));
+       memset(&startwork, 0, sizeof(struct timespec));
+       memset(&endwork, 0, sizeof(struct timespec));   
+       //last working time in microseconds
+       unsigned long workingtime = 0;
+       int i = 0;
+
+       //build the family
+       create_process_family(&pf, pid);
+       struct list_node *node;
+       
+       if (verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
 
-               //open a directory stream to /proc directory
-               if ((dip = opendir("/proc")) == NULL) {
-                       perror("opendir");
-                       return -1;
-               }
+       while(1) {
 
-               //read in from /proc and seek for process dirs
-               while ((dit = readdir(dip)) != NULL) {
-                       //get pid
-                       if (pid==atoi(dit->d_name)) {
-                               //pid detected
-                               if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
-                                       //process is ok!
-                                       goto done;
-                               }
-                               else {
-                                       fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
+               if (i%100==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 j;
+                               node = pf.members.last;
+                               for (j=0; j<newborn; j++) {
+                                       printf("%d", ((struct process*)(node->data))->pid);
+                                       if (j<newborn-1) printf(" ");
+                                       node = node->previous;
                                }
+                               printf(")\n");
                        }
                }
 
-               //close the dir stream and check for errors
-               if (closedir(dip) == -1) {
-                       perror("closedir");
-                       return -1;
-               }
-
-               //no suitable target found
-               if (i++==0) {
-                       if (lazy) {
-                               fprintf(stderr,"No process found\n");
-                               exit(2);
-                       }
-                       else {
-                               printf("Warning: no target process found. Waiting for it...\n");
+               //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;
+
+               //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) {
+                               //process is dead, remove it from family
+                               remove_process_from_family(&pf, proc->pid);
+                               fprintf(stderr,"Process %d dead!\n", proc->pid);
                        }
+                       pcpu += proc->history->usage.pcpu;
+                       workingrate += proc->history->usage.workingrate;
                }
+               //average value
+               workingrate /= pf.members.count;
 
-               //sleep for a while
-               sleep(2);
-       }
+               //TODO: make workingtime customized for each process, now it's equal for all
 
-done:
-       printf("Process %d detected\n",pid);
-       //now set high priority, if possible
-       if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
-               printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
-       }
-       return 0;
-
-}
-
-//this function periodically scans process list and looks for executable path names
-//it should be executed in a low priority context, since precise timing does not matter
-//if a process is found then its pid is returned
-//process: the name of the wanted process, can be an absolute path name to the executable file
-//         or simply its name
-//return: pid of the found process
-int getpidof(const char *process) {
-
-       //set low priority
-       if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
-               printf("Warning: cannot renice\n");
-       }
-
-       char exelink[20];
-       char exepath[PATH_MAX+1];
-       int pid=0;
-       int i=0;
-
-       while(1) {
-
-               DIR *dip;
-               struct dirent *dit;
-
-               //open a directory stream to /proc directory
-               if ((dip = opendir("/proc")) == NULL) {
-                       perror("opendir");
-                       return -1;
+               //adjust work and sleep time slices
+               if (pcpu>0) {
+                       twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000/pcpu*workingrate,CONTROL_SLOT*1000);
                }
-
-               //read in from /proc and seek for process dirs
-               while ((dit = readdir(dip)) != NULL) {
-                       //get pid
-                       pid=atoi(dit->d_name);
-                       if (pid>0) {
-                               sprintf(exelink,"/proc/%d/exe",pid);
-                               int size=readlink(exelink,exepath,sizeof(exepath));
-                               if (size>0) {
-                                       int found=0;
-                                       if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
-                                               //process starts with / then it's an absolute path
-                                               found=1;
-                                       }
-                                       else {
-                                               //process is the name of the executable file
-                                               if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
-                                                       found=1;
-                                               }
-                                       }
-                                       if (found==1) {
-                                               if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
-                                                       //process is ok!
-                                                       goto done;
-                                               }
-                                               else {
-                                                       fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
-                                               }
-                                       }
-                               }
-                       }
+               else if (pcpu==0) {
+                       twork.tv_nsec = CONTROL_SLOT*1000;
                }
+               else if (pcpu==-1) {
+                       //not yet a valid idea of cpu usage
+                       pcpu = limit;
+                       workingrate = limit;
+                       twork.tv_nsec = MIN(CONTROL_SLOT*limit*1000,CONTROL_SLOT*1000);
+               }
+               tsleep.tv_nsec = CONTROL_SLOT*1000-twork.tv_nsec;
 
-               //close the dir stream and check for errors
-               if (closedir(dip) == -1) {
-                       perror("closedir");
-                       return -1;
+               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);
                }
 
-               //no suitable target found
-               if (i++==0) {
-                       if (lazy) {
-                               fprintf(stderr,"No process found\n");
-                               exit(2);
-                       }
-                       else {
-                               printf("Warning: no target process found. Waiting for it...\n");
+               //resume processes
+               for (node=pf.members.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
+                               fprintf(stderr,"Process %d dead!\n", proc->pid);
+                               remove_process_from_family(&pf, proc->pid);
                        }
                }
 
-               //sleep for a while
-               sleep(2);
-       }
-
-done:
-       printf("Process %d detected\n",pid);
-       //now set high priority, if possible
-       if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
-               printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
-       }
-       return pid;
-
-}
-
-//SIGINT and SIGTERM signal handler
-void quit(int sig) {
-       //let the process continue if it's stopped
-       kill(pid,SIGCONT);
-       printf("Exiting...\n");
-       exit(0);
-}
-
-//get jiffies count from /proc filesystem
-int getjiffies(int pid) {
-       static char stat[20];
-       static char buffer[1024];
-       sprintf(stat,"/proc/%d/stat",pid);
-       FILE *f=fopen(stat,"r");
-       if (f==NULL) return -1;
-       fgets(buffer,sizeof(buffer),f);
-       fclose(f);
-       char *p=buffer;
-       p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
-       int sp=12;
-       while (sp--)
-               p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
-       //user mode jiffies
-       int utime=atoi(p+1);
-       p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
-       //kernel mode jiffies
-       int ktime=atoi(p+1);
-       return utime+ktime;
-}
-
-//process instant photo
-struct process_screenshot {
-       struct timespec when;   //timestamp
-       int jiffies;    //jiffies count of the process
-       int cputime;    //microseconds of work from previous screenshot to current
-};
-
-//extracted process statistics
-struct cpu_usage {
-       float pcpu;
-       float workingrate;
-};
-
-//this function is an autonomous dynamic system
-//it works with static variables (state variables of the system), that keep memory of recent past
-//its aim is to estimate the cpu usage of the process
-//to work properly it should be called in a fixed periodic way
-//perhaps i will put it in a separate thread...
-int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
-       #define MEM_ORDER 10
-       //circular buffer containing last MEM_ORDER process screenshots
-       static struct process_screenshot ps[MEM_ORDER];
-       //the last screenshot recorded in the buffer
-       static int front=-1;
-       //the oldest screenshot recorded in the buffer
-       static int tail=0;
-
-       if (pusage==NULL) {
-               //reinit static variables
-               front=-1;
-               tail=0;
-               return 0;
-       }
-
-       //let's advance front index and save the screenshot
-       front=(front+1)%MEM_ORDER;
-       int j=getjiffies(pid);
-       if (j>=0) ps[front].jiffies=j;
-       else return -1; //error: pid does not exist
-       clock_gettime(CLOCK_REALTIME,&(ps[front].when));
-       ps[front].cputime=last_working_quantum;
-
-       //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
-       int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
-
-       if (size==1) {
-               //not enough samples taken (it's the first one!), return -1
-               pusage->pcpu=-1;
-               pusage->workingrate=1;
-               return 0;
-       }
-       else {
-               //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
-               long dt=timediff(&(ps[front].when),&(ps[tail].when));
-               long dtwork=0;
-               int i=(tail+1)%MEM_ORDER;
-               int max=(front+1)%MEM_ORDER;
-               do {
-                       dtwork+=ps[i].cputime;
-                       i=(i+1)%MEM_ORDER;
-               } while (i!=max);
-               int used=ps[front].jiffies-ps[tail].jiffies;
-               float usage=(used*1000000.0/HZ)/dtwork;
-               pusage->workingrate=1.0*dtwork/dt;
-               pusage->pcpu=usage*pusage->workingrate;
-               if (size==MEM_ORDER)
-                       tail=(tail+1)%MEM_ORDER;
-               return 0;
+               //now processes are free to run (same working slice for all)
+               clock_gettime(CLOCK_REALTIME,&startwork);
+               nanosleep(&twork,NULL);
+               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);
+                       }
+               }
+               //now the process is forced to sleep
+               nanosleep(&tsleep,NULL);
+               i++;
        }
-       #undef MEM_ORDER
-}
-
-void print_caption() {
-       printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
-}
-
-void print_usage(FILE *stream,int exit_code) {
-       fprintf(stream, "Usage: %s TARGET [OPTIONS...]\n",program_name);
-       fprintf(stream, "   TARGET must be exactly one of these:\n");
-       fprintf(stream, "      -p, --pid=N        pid of the process\n");
-       fprintf(stream, "      -e, --exe=FILE     name of the executable program file\n");
-       fprintf(stream, "      -P, --path=PATH    absolute path name of the executable program file\n");
-       fprintf(stream, "   OPTIONS\n");
-       fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 0 to 100 (mandatory)\n");
-       fprintf(stream, "      -v, --verbose      show control statistics\n");
-       fprintf(stream, "      -z, --lazy         exit if there is no suitable target process, or if it dies\n");
-       fprintf(stream, "      -h, --help         display this help and exit\n");
-       exit(exit_code);
+       cleanup_process_family(&pf);
 }
 
 int main(int argc, char **argv) {
@@ -351,59 +268,60 @@ 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);
+       cpulimit_pid = getpid();
+
+       //argument variables
+       const char *exe = NULL;
+       int perclimit = 0;
+       int pid_ok = 0;
+       int process_ok = 0;
+       int limit_ok = 0;
+       int pid = 0;
+
        //parse arguments
        int next_option;
-       /* A string listing valid short options letters. */
-       const char* short_options="p:e:P:l:vzh";
-       /* An array describing valid long options. */
+    int option_index = 0;
+       //A string listing valid short options letters
+       const char* short_options = "p:e:l:vzh";
+       //An array describing valid long options
        const struct option long_options[] = {
-               { "pid", 0, NULL, 'p' },
-               { "exe", 1, NULL, 'e' },
-               { "path", 0, NULL, 'P' },
-               { "limit", 0, NULL, 'l' },
-               { "verbose", 0, NULL, 'v' },
-               { "lazy", 0, NULL, 'z' },
-               { "help", 0, NULL, 'h' },
-               { NULL, 0, NULL, 0 }
+               { "pid",        required_argument, NULL,     'p' },
+               { "exe",        required_argument, NULL,     'e' },
+               { "limit",      required_argument, NULL,     'l' },
+               { "verbose",    no_argument,       &verbose, 'v' },
+               { "lazy",       no_argument,       &lazy,    'z' },
+               { "help",       no_argument,       NULL,     'h' },
+               { 0,            0,                 0,         0  }
        };
-       //argument variables
-       const char *exe=NULL;
-       const char *path=NULL;
-       int perclimit=0;
-       int pid_ok=0;
-       int process_ok=0;
-       int limit_ok=0;
 
        do {
-               next_option = getopt_long (argc, argv, short_options,long_options, NULL);
+               next_option = getopt_long(argc, argv, short_options,long_options, &option_index);
                switch(next_option) {
                        case 'p':
-                               pid=atoi(optarg);
-                               pid_ok=1;
+                               pid = atoi(optarg);
+                               //todo: verify pid is valid
+                               pid_ok = 1;
+                               process_ok = 1;
                                break;
                        case 'e':
-                               exe=optarg;
-                               process_ok=1;
-                               break;
-                       case 'P':
-                               path=optarg;
-                               process_ok=1;
+                               exe = optarg;
+                               process_ok = 1;
                                break;
                        case 'l':
-                               perclimit=atoi(optarg);
-                               limit_ok=1;
+                               perclimit = atoi(optarg);
+                               limit_ok = 1;
                                break;
                        case 'v':
-                               verbose=1;
+                               verbose = 1;
                                break;
                        case 'z':
-                               lazy=1;
+                               lazy = 1;
                                break;
                        case 'h':
-                               print_usage (stdout, 1);
+                               print_usage(stdout, 1);
                                break;
                        case '?':
-                               print_usage (stderr, 1);
+                               print_usage(stderr, 1);
                                break;
                        case -1:
                                break;
@@ -412,126 +330,91 @@ int main(int argc, char **argv) {
                }
        } while(next_option != -1);
 
-       if (!process_ok && !pid_ok) {
-               fprintf(stderr,"Error: You must specify a target process\n");
-               print_usage (stderr, 1);
+       if (pid!=0) {
+               lazy = 1;
+       }
+       
+       if (!process_ok) {
+               fprintf(stderr,"Error: You must specify a target process, by name or by PID\n");
+               print_usage(stderr, 1);
                exit(1);
        }
-       if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
-               fprintf(stderr,"Error: You must specify exactly one target process\n");
-               print_usage (stderr, 1);
+       if (pid_ok && exe!=NULL) {
+               fprintf(stderr, "Error: You must specify exactly one process, by name or by PID\n");
+               print_usage(stderr, 1);
                exit(1);
        }
        if (!limit_ok) {
-               fprintf(stderr,"Error: You must specify a cpu limit\n");
-               print_usage (stderr, 1);
+               fprintf(stderr,"Error: You must specify a cpu limit percentage\n");
+               print_usage(stderr, 1);
                exit(1);
        }
-       float limit=perclimit/100.0;
-       if (limit<0 || limit >1) {
-               fprintf(stderr,"Error: limit must be in the range 0-100\n");
-               print_usage (stderr, 1);
+       float limit = perclimit/100.0;
+       int cpu_count = get_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);
                exit(1);
        }
        //parameters are all ok!
-       signal(SIGINT,quit);
-       signal(SIGTERM,quit);
-
-       //time quantum in microseconds. it's splitted in a working period and a sleeping one
-       int period=100000;
-       struct timespec twork,tsleep;   //working and sleeping intervals
-       memset(&twork,0,sizeof(struct timespec));
-       memset(&tsleep,0,sizeof(struct timespec));
-
-wait_for_process:
-
-       //look for the target process..or wait for it
-       if (exe!=NULL)
-               pid=getpidof(exe);
-       else if (path!=NULL)
-               pid=getpidof(path);
+       signal(SIGINT, quit);
+       signal(SIGTERM, quit);
+
+       //try to renice with the best value
+       int old_priority = getpriority(PRIO_PROCESS, 0);
+       int priority = old_priority;
+       while (setpriority(PRIO_PROCESS, 0, priority-1) == 0 && priority>MAX_PRIORITY) {
+               priority--;     
+       }
+       if (priority != old_priority) {
+               printf("Priority changed to %d\n", priority);
+       }
        else {
-               waitforpid(pid);
+               printf("Cannot change priority\n");
        }
-       //process detected...let's play
-
-       //init compute_cpu_usage internal stuff
-       compute_cpu_usage(0,0,NULL);
-       //main loop counter
-       int i=0;
-
-       struct timespec startwork,endwork;
-       long workingtime=0;             //last working time in microseconds
-
-       if (verbose) print_caption();
-
-       float pcpu_avg=0;
-
-       //here we should already have high priority, for time precision
+       
        while(1) {
-
-               //estimate how much the controlled process is using the cpu in its working interval
-               struct cpu_usage cu;
-               if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
-                       fprintf(stderr,"Process %d dead!\n",pid);
-                       if (lazy) exit(2);
-                       //wait until our process appears
-                       goto wait_for_process;          
-               }
-
-               //cpu actual usage of process (range 0-1)
-               float pcpu=cu.pcpu;
-               //rate at which we are keeping active the process (range 0-1)
-               float workingrate=cu.workingrate;
-
-               //adjust work and sleep time slices
-               if (pcpu>0) {
-                       twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
-               }
-               else if (pcpu==0) {
-                       twork.tv_nsec=period*1000;
-               }
-               else if (pcpu==-1) {
-                       //not yet a valid idea of cpu usage
-                       pcpu=limit;
-                       workingrate=limit;
-                       twork.tv_nsec=min(period*limit*1000,period*1000);
-               }
-               tsleep.tv_nsec=period*1000-twork.tv_nsec;
-
-               //update average usage
-               pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
-
-               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);
+               //look for the target process..or wait for it
+               int ret = 0;
+               if (pid_ok) {
+                       //search by pid
+                       ret = look_for_process_by_pid(pid);
+                       if (ret == 0) {
+                               printf("No process found\n");
+                       }
+                       else if (ret < 0) {
+                               printf("Process found but you aren't allowed to control it\n");
+                       }
                }
-
-               if (limit<1 && limit>0) {
-                       //resume process
-                       if (kill(pid,SIGCONT)!=0) {
-                               fprintf(stderr,"Process %d dead!\n",pid);
-                               if (lazy) exit(2);
-                               //wait until our process appears
-                               goto wait_for_process;
+               else {
+                       //search by file or path name
+                       ret = look_for_process_by_name(exe);
+                       if (ret == 0) {
+                               printf("No process found\n");
+                       }
+                       else if (ret < 0) {
+                               printf("Process found but you aren't allowed to control it\n");
+                       }
+                       else {
+                               pid = ret;
                        }
                }
-
-               clock_gettime(CLOCK_REALTIME,&startwork);
-               nanosleep(&twork,NULL);         //now process is working        
-               clock_gettime(CLOCK_REALTIME,&endwork);
-               workingtime=timediff(&endwork,&startwork);
-
-               if (limit<1) {
-                       //stop process, it has worked enough
-                       if (kill(pid,SIGSTOP)!=0) {
-                               fprintf(stderr,"Process %d dead!\n",pid);
-                               if (lazy) exit(2);
-                               //wait until our process appears
-                               goto wait_for_process;
+               if (ret > 0) {
+                       if (ret == cpulimit_pid) {
+                               printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret);
+                               exit(1);
                        }
-                       nanosleep(&tsleep,NULL);        //now process is sleeping
+                       printf("Process %d found\n", pid);
+                       //control
+                       limit_process(pid, limit);
                }
-               i++;
+               if (lazy) {
+                       printf("Giving up...\n");
+                       break;
+               }
+               sleep(2);
        }
-
+       
+       return 0;
 }
+