Imported Upstream version 2.2
[debian/cpulimit.git] / cpulimit.c
1 /**
2  * This program is licensed under the GNU General Public License,
3  * version 2. A copy of the license can be found in the accompanying
4  * LICENSE file.
5  *
6  **********************************************************************
7  *
8  * Simple program to limit the cpu usage of a process
9  * If you modify this code, send me a copy please
10  *
11  * Author:  Angelo Marletta
12  * Date:    26/06/2005
13  * Version: 1.1
14  *
15  * Modifications and updates by: Jesse Smith
16  * Date: May 4, 2011
17  * Version 1.2 
18  * Date: Jan 29, 2013
19  * Version 1.2 and newer
20  *
21  * Modifications and updates by: Hasnain Lakhani
22  * Date: Mar 26, 2014
23  * Version 2.1
24  */
25
26
27 #include <getopt.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <sys/resource.h>
38 #include <string.h>
39 #include <dirent.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <limits.h>    // for compatibility
43
44 #ifdef __APPLE__
45 #include <mach/clock.h>
46 #include <mach/mach.h>
47 #endif
48
49
50 #ifdef FREEBSD
51 #include <fcntl.h>
52 #include <kvm.h>
53 #include <paths.h>
54 #include <sys/param.h>
55 #include <sys/sysctl.h>
56 #include <sys/user.h>
57 #endif
58
59
60 //kernel time resolution (inverse of one jiffy interval) in Hertz
61 //i don't know how to detect it, then define to the default (not very clean!)
62 #define HZ 100
63
64 //some useful macro
65 #define min(a,b) (a<b?a:b)
66 #define max(a,b) (a>b?a:b)
67
68 // For platforms without PATH_MAX
69 #ifndef PATH_MAX
70 #define PATH_MAX 4096
71 #endif
72
73 #define BEST_PRIORITY -10
74
75 #ifndef TRUE
76 #define TRUE 1
77 #endif
78 #ifndef FALSE
79 #define FALSE 0
80 #endif
81
82 #ifndef VERSION
83 #define VERSION 2.1
84 #endif
85
86 //pid of the controlled process
87 pid_t pid = 0;
88 pid_t my_pid;     // this process's PID
89
90 //executable file name
91 char *program_name;
92 //verbose mode
93 int verbose = FALSE;
94 //lazy mode
95 int lazy = FALSE;
96 // is higher priority nice possible?
97 int nice_lim;
98
99 // number of CPUs we detected
100 int NCPU;
101
102 // quiet mode
103 int quiet = FALSE;
104
105 // What signal should we send to the watched process
106 // when cpulimit exits?
107 int send_signal = SIGCONT;
108
109 //reverse byte search
110 // void *memrchr(const void *s, int c, size_t n);
111
112 #define MAX_SIGNAL 7
113 const char *SIGNAL_NAME[MAX_SIGNAL] = { "SIGHUP", "SIGINT", "SIGQUIT", 
114                                  "SIGKILL", "SIGTERM", "SIGSTOP", "SIGCONT" };
115 const int SIGNAL_VALUE[MAX_SIGNAL] = { SIGHUP, SIGINT, SIGQUIT,
116                                   SIGKILL, SIGTERM, SIGSTOP, SIGCONT };
117
118
119 //return ta-tb in microseconds (no overflow checks!)
120 inline long timediff(const struct timespec *ta,const struct timespec *tb) {
121     unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
122     return us;
123 }
124
125
126
127 int Check_Us(pid_t target_pid)
128 {
129    pid_t this_pid;
130
131    this_pid = getpid();
132    if (this_pid == target_pid)
133    {
134       fprintf(stderr, "We cannot throttle ourselves.\n");
135       exit(7);
136    }
137    return TRUE;
138 }
139
140
141 int waitforpid(int pid) {
142         //switch to low priority
143         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
144         /*
145         if ( (nice_lim < INT_MAX) && 
146              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
147                 printf("Warning: cannot renice\n");
148         }
149         */
150         int i=0;
151
152         while(1) {
153
154                 DIR *dip;
155                 struct dirent *dit;
156
157                 //open a directory stream to /proc directory
158                 if ((dip = opendir("/proc")) == NULL) {
159                         perror("opendir");
160                         return -1;
161                 }
162
163                 //read in from /proc and seek for process dirs
164                 while ((dit = readdir(dip)) != NULL) {
165                         //get pid
166                         if (pid==atoi(dit->d_name)) {
167                                 //pid detected
168                                 Check_Us(pid);
169                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
170                                         //process is ok!
171                                         if (closedir(dip) == -1) {
172                                            perror("closedir");
173                                            return -1;
174                                         }
175                                         goto done;
176                                 }
177                                 else {
178                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
179                                 }
180                         }
181                 }
182
183                 //close the dir stream and check for errors
184                 if (closedir(dip) == -1) {
185                         perror("closedir");
186                         return -1;
187                 }
188
189                 //no suitable target found
190                 if (i++==0) {
191                         if (lazy) {
192                                 fprintf(stderr,"No process found\n");
193                                 exit(2);
194                         }
195                         else {
196                                 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
197                         }
198                 }
199
200                 //sleep for a while
201                 sleep(2);
202         }
203
204 done:
205     if (!quiet)
206         printf("Process %d detected\n",pid);
207         //now set high priority, if possible
208         // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
209         /*
210         if ( (nice_lim < INT_MAX) &&
211              (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
212                 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
213         }
214         */
215         return 0;
216
217 }
218
219 //this function periodically scans process list and looks for executable path names
220 //it should be executed in a low priority context, since precise timing does not matter
221 //if a process is found then its pid is returned
222 //process: the name of the wanted process, can be an absolute path name to the executable file
223 //         or simply its name
224 //return: pid of the found process
225 int getpidof(const char *process) {
226
227         //set low priority
228         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
229         /*
230         if ( (nice_lim < INT_MAX) &&
231              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
232                 printf("Warning: cannot renice\n");
233         }
234         */
235         char exelink[20];
236         char exepath[PATH_MAX+1];
237         int pid=0;
238         int i=0;
239
240         while(1) {
241
242                 DIR *dip;
243                 struct dirent *dit;
244
245                 //open a directory stream to /proc directory
246                 if ((dip = opendir("/proc")) == NULL) {
247                         perror("opendir");
248                         return -1;
249                 }
250
251                 //read in from /proc and seek for process dirs
252                 while ((dit = readdir(dip)) != NULL) {
253                         //get pid
254                         pid=atoi(dit->d_name);
255                         if (pid>0) {
256                                 sprintf(exelink,"/proc/%d/exe",pid);
257                                 int size=readlink(exelink,exepath,sizeof(exepath));
258                                 if (size>0) {
259                                         int found=0;
260                                         if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
261                                                 //process starts with / then it's an absolute path
262                                                 found=1;
263                                         }
264                                         else {
265                                                 //process is the name of the executable file
266                                                 if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
267                                                         found=1;
268                                                 }
269                                         }
270                                         if (found==1) {
271                                         Check_Us(pid);
272                                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
273                                                         //process is ok!
274                                                         if (closedir(dip) == -1) {
275                                                           perror("closedir");
276                                                           return -1;
277                                                         }
278                                                         goto done;
279                                                 }
280                                                 else {
281                                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
282                                                 }
283                                         }
284                                 }
285                         }
286                 }
287
288                 //close the dir stream and check for errors
289                 if (closedir(dip) == -1) {
290                         perror("closedir");
291                         return -1;
292                 }
293
294                 //no suitable target found
295                 if (i++==0) {
296                         if (lazy) {
297                                 fprintf(stderr,"No process found\n");
298                                 exit(2);
299                         }
300                         else {
301                                 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
302                         }
303                 }
304
305                 //sleep for a while
306                 sleep(2);
307         }
308
309 done:
310     if (!quiet)
311         printf("Process %d detected\n",pid);
312         //now set high priority, if possible
313         // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
314         /*
315         if ( (nice_lim < INT_MAX) &&
316              (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
317                 printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
318         }
319         */
320         return pid;
321
322 }
323
324 //SIGINT and SIGTERM signal handler
325 void quit(int sig) {
326         //let the process continue if we are stopped
327         kill(pid, send_signal);
328         printf("Exiting...\n");
329         exit(0);
330 }
331
332
333 #ifdef FREEBSD
334 //get jiffies count from /proc filesystem
335 int getjiffies(int pid)
336 {
337    kvm_t *my_kernel = NULL;
338    struct kinfo_proc *process_data = NULL;
339    int processes;
340    int my_jiffies = -1;
341
342    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
343    if (! my_kernel)
344    {
345       fprintf(stderr, "Error opening kernel vm. You should be running as root.\n");
346       return -1;
347    }
348
349    process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes);
350    if ( (process_data) && (processes >= 1) )
351        my_jiffies = process_data->ki_runtime;
352    
353    kvm_close(my_kernel);
354    if (my_jiffies >= 0)
355      my_jiffies /= 1000;
356    return my_jiffies;
357 }
358
359 #endif
360
361 #ifdef LINUX
362 int getjiffies(int pid) {
363         static char stat[20];
364         static char buffer[1024];
365         char *p;
366         sprintf(stat,"/proc/%d/stat",pid);
367         FILE *f=fopen(stat,"r");
368         if (f==NULL) return -1;
369         p = fgets(buffer,sizeof(buffer),f);
370         fclose(f);
371         // char *p=buffer;
372         if (p)
373         {
374           p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
375           int sp=12;
376           while (sp--)
377                 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
378           //user mode jiffies
379           int utime=atoi(p+1);
380           p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
381           //kernel mode jiffies
382           int ktime=atoi(p+1);
383           return utime+ktime;
384         }
385         // could not read info
386         return -1;
387 }
388 #endif
389
390
391 //process instant photo
392 struct process_screenshot {
393         struct timespec when;   //timestamp
394         int jiffies;    //jiffies count of the process
395         int cputime;    //microseconds of work from previous screenshot to current
396 };
397
398 //extracted process statistics
399 struct cpu_usage {
400         float pcpu;
401         float workingrate;
402 };
403
404 //this function is an autonomous dynamic system
405 //it works with static variables (state variables of the system), that keep memory of recent past
406 //its aim is to estimate the cpu usage of the process
407 //to work properly it should be called in a fixed periodic way
408 //perhaps i will put it in a separate thread...
409 int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
410         #define MEM_ORDER 10
411         //circular buffer containing last MEM_ORDER process screenshots
412         static struct process_screenshot ps[MEM_ORDER];
413         //the last screenshot recorded in the buffer
414         static int front=-1;
415         //the oldest screenshot recorded in the buffer
416         static int tail=0;
417
418         if (pusage==NULL) {
419                 //reinit static variables
420                 front=-1;
421                 tail=0;
422                 return 0;
423         }
424
425         //let's advance front index and save the screenshot
426         front=(front+1)%MEM_ORDER;
427         int j=getjiffies(pid);
428         if (j>=0) ps[front].jiffies=j;
429         else return -1; //error: pid does not exist
430
431         #ifdef __APPLE__
432         // OS X does not have clock_gettime, use clock_get_time
433         clock_serv_t cclock;
434         mach_timespec_t mts;
435         host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
436         clock_get_time(cclock, &mts);
437         mach_port_deallocate(mach_task_self(), cclock);
438         ps[front].when.tv_sec = mts.tv_sec;
439         ps[front].when.tv_nsec = mts.tv_nsec;
440
441         #else
442         // Linux and BSD can use real time
443         clock_gettime(CLOCK_REALTIME,&(ps[front].when));
444         ps[front].cputime=last_working_quantum;
445         #endif
446         //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
447         int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
448
449         if (size==1) {
450                 //not enough samples taken (it's the first one!), return -1
451                 pusage->pcpu=-1;
452                 pusage->workingrate=1;
453                 return 0;
454         }
455         else {
456                 //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
457                 long dt=timediff(&(ps[front].when),&(ps[tail].when));
458                 long dtwork=0;
459                 int i=(tail+1)%MEM_ORDER;
460                 int max=(front+1)%MEM_ORDER;
461                 do {
462                         dtwork+=ps[i].cputime;
463                         i=(i+1)%MEM_ORDER;
464                 } while (i!=max);
465                 int used=ps[front].jiffies-ps[tail].jiffies;
466                 float usage=(used*1000000.0/HZ)/dtwork;
467                 pusage->workingrate=1.0*dtwork/dt;
468                 pusage->pcpu=usage*pusage->workingrate;
469                 if (size==MEM_ORDER)
470                         tail=(tail+1)%MEM_ORDER;
471                 return 0;
472         }
473         #undef MEM_ORDER
474 }
475
476 void print_caption() {
477         printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
478 }
479
480
481 void increase_priority()
482 {
483         //find the best available nice value
484         int old_priority = getpriority(PRIO_PROCESS, 0);
485         int priority = old_priority;
486         while ( (setpriority(PRIO_PROCESS, 0, priority-1) == 0) &&
487                 (priority > BEST_PRIORITY) )
488         {
489                 priority--;
490         }
491         if (priority != old_priority) {
492                 if (verbose) printf("Priority changed to %d\n", priority);
493         }
494         else {
495                 if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
496         }
497
498
499 }
500
501
502
503 void print_usage(FILE *stream,int exit_code) {
504         fprintf(stream, "CPUlimit version %1.1f\n", VERSION);
505         fprintf(stream, "Usage: %s TARGET [OPTIONS...] [-- PROGRAM]\n",program_name);
506         fprintf(stream, "   TARGET must be exactly one of these:\n");
507         fprintf(stream, "      -p, --pid=N        pid of the process\n");
508         fprintf(stream, "      -e, --exe=FILE     name of the executable program file\n");
509         fprintf(stream, "                         The -e option only works when\n");
510         fprintf(stream, "                         cpulimit is run with admin rights.\n");
511         fprintf(stream, "      -P, --path=PATH    absolute path name of the\n");
512         fprintf(stream, "                         executable program file\n");
513         fprintf(stream, "   OPTIONS\n");
514         fprintf(stream, "      -b  --background   run in background\n");
515         fprintf(stream, "      -c  --cpu=N        override the detection of CPUs on the machine.\n");
516         fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
517         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
518         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
519         fprintf(stream, "      -q, --quiet        run in quiet mode (only print errors).\n");
520         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
521         fprintf(stream, "                         instead of just throttling them.\n");
522         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
523         fprintf(stream, "                         been killed. Works with the -k flag.\n");
524         fprintf(stream, "      -s, --signal=SIG   Send this signal to the watched process when cpulimit exits.\n");
525         fprintf(stream, "                         Signal should be specificed as a number or \n");
526         fprintf(stream, "                         SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.\n");
527         fprintf(stream, "      -v, --verbose      show control statistics\n");
528         fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
529         fprintf(stream, "                         or if it dies\n");
530         fprintf(stream, "          --             This is the final CPUlimit option. All following\n");
531         fprintf(stream, "                         options are for another program we will launch.\n");
532         fprintf(stream, "      -h, --help         display this help and exit\n");
533         exit(exit_code);
534 }
535
536
537
538 // Get the number of CPU cores on this machine.
539 int get_ncpu()
540 {
541         int ncpu = 1;
542 #ifdef _SC_NPROCESSORS_ONLN
543         ncpu = sysconf(_SC_NPROCESSORS_ONLN);
544 #endif
545         return ncpu;
546 }
547
548
549 // This function attempts to figure out what signal we should send
550 // target processes based on a command line paramter. First we check
551 // for text such as SIGINT, SIGCONT, SIGSTOP, etc. If no match is found
552 // then we assume the value given is a number and use that.
553 int Translate_Signal(char *my_signal)
554 {
555     int signal_value;
556     int index = 0, found = FALSE;
557     // first check to see if we were passed a string
558     while ( (index < MAX_SIGNAL) && (! found) )
559     {
560         if (! strcmp(my_signal, SIGNAL_NAME[index]) )
561         {
562             found = TRUE;
563             signal_value = SIGNAL_VALUE[index];
564         }
565         else
566            index++;
567     }
568
569     // no value found, try a number
570     if (! found)
571        signal_value = atoi(my_signal);
572
573     return signal_value;
574 }
575
576
577
578 int main(int argc, char **argv) {
579
580         //get program name
581         // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
582         // program_name = p==NULL?argv[0]:(p+1);
583         program_name = argv[0];
584         int run_in_background = FALSE;
585         //parse arguments
586         int next_option;
587         /* A string listing valid short options letters. */
588         const char* short_options="p:e:P:l:c:s:bqkrvzh";
589         /* An array describing valid long options. */
590         const struct option long_options[] = {
591                 { "pid", required_argument, NULL, 'p' },
592                 { "exe", required_argument, NULL, 'e' },
593                 { "path", required_argument, NULL, 'P' },
594                 { "limit", required_argument, NULL, 'l' },
595                 { "background", no_argument, NULL, 'b' },
596                 { "quiet", no_argument, NULL, 'q' },
597                 { "verbose", no_argument, NULL, 'v' },
598                 { "lazy", no_argument, NULL, 'z' },
599                 { "help", no_argument, NULL, 'h' },
600                 { "cpu", required_argument, NULL, 'c'},
601                 { "signal", required_argument, NULL, 's'},
602                 { NULL, 0, NULL, 0 }
603         };
604         //argument variables
605         const char *exe=NULL;
606         const char *path=NULL;
607         int perclimit=0;
608         int pid_ok = FALSE;
609         int process_ok = FALSE;
610         int limit_ok = FALSE;
611         int last_known_argument = 0;
612         int kill_process = FALSE;   // kill process instead of stopping it
613         int restore_process = FALSE;  // restore killed process
614         // struct rlimit maxlimit;
615
616         NCPU = get_ncpu();
617
618         opterr = 0;      // avoid unwanted error messages for unknown parameters
619         do {
620                 next_option = getopt_long (argc, argv, short_options,long_options, NULL);
621                 switch(next_option) {
622                         case 'b':
623                                 run_in_background = TRUE;
624                                 last_known_argument++;
625                                 break;
626                         case 'p':
627                                 pid=atoi(optarg);
628                                 if (pid)   // valid PID
629                                 {
630                                   pid_ok = TRUE;
631                                   lazy = TRUE;
632                                 }
633                                 last_known_argument += 2;
634                                 break;
635                         case 'e':
636                                 exe=optarg;
637                                 process_ok = TRUE;
638                                 last_known_argument += 2;
639                                 break;
640                         case 'P':
641                                 path=optarg;
642                                 process_ok = TRUE;
643                                 last_known_argument += 2;
644                                 break;
645                         case 'l':
646                                 perclimit=atoi(optarg);
647                                 limit_ok = TRUE;
648                                 last_known_argument += 2;
649                                 break;
650                         case 'c':
651                                 NCPU = atoi(optarg);
652                                 last_known_argument += 2;
653                                 break;
654                         case 's':
655                                 send_signal = Translate_Signal(optarg);
656                                 if ( (send_signal < 1) || (send_signal > 35) )
657                                 {
658                                     fprintf(stderr, "Specified exit signal is not recognized or not within bounds (1-35). Using SIGCONT.\n");
659                                     send_signal = SIGCONT;
660                                 }
661                                 last_known_argument += 2;
662                         case 'k':
663                                 kill_process = TRUE;
664                                 last_known_argument++;
665                                 break;
666                         case 'r':
667                                 restore_process = TRUE;
668                                 last_known_argument++;
669                                 break;
670
671                         case 'v':
672                                 verbose = TRUE;
673                                 last_known_argument++;
674                                 break;
675                         case 'q':
676                                 quiet = TRUE;
677                                 last_known_argument++;
678                                 break;
679                         case 'z':
680                                 lazy = TRUE;
681                                 last_known_argument++;
682                                 break;
683                         case 'h':
684                                 print_usage (stdout, 1);
685                                 last_known_argument++;
686                                 break;
687                         case 'o':
688                                 last_known_argument++;
689                                 next_option = -1;
690                                 break;
691                         case '?':
692                                 print_usage (stderr, 1);
693                                 last_known_argument++;
694                                 break;
695                         case -1:
696                                 break;
697                         // default:
698                         //      abort();
699                 }
700         } while(next_option != -1);
701
702
703         // try to launch a program passed on the command line
704         // But only if we do not already have a PID to watch
705         if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) )
706         {
707            last_known_argument++;
708            // if we stopped on "--" jump to the next parameter
709            if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) )
710                last_known_argument++;
711            pid_t forked_pid;
712            // try to launch remaining arguments
713            if (verbose)
714            {
715                int index = last_known_argument;
716                printf("Launching %s", argv[index]);
717                for (index = last_known_argument + 1; index < argc; index++)
718                     printf(" %s", argv[index]);
719                printf(" with limit %d\n", perclimit);
720            }
721            forked_pid = fork();
722            if (forked_pid == -1)  // error
723            {
724                printf("Failed to launch specified process.\n");
725                exit(1);
726            }
727            else if (forked_pid == 0)   // target child
728            {
729               execvp(argv[last_known_argument],
730                      &(argv[last_known_argument]) );
731               exit(2);
732            }
733            else     // parent who will now fork the throttler
734            {
735               pid_t limit_pid;
736               // if we are planning to kill a process, give it
737               // a running head start to avoid death at start-up
738               if (kill_process)
739                  sleep(5);
740      
741               limit_pid = fork();
742               if (limit_pid == 0)   // child
743               {
744                  pid = forked_pid;    // the first child
745                  lazy = TRUE;
746                  pid_ok = TRUE;
747                  if (verbose)
748                    printf("Throttling process %d\n", (int) pid);
749               }
750               else    // parent
751                 exit(0);
752            }
753
754            /*
755            else if (forked_pid == 0)   // child
756            {
757                lazy = TRUE;
758                pid_ok = TRUE;
759                pid = getppid();
760                if (verbose)
761                   printf("Throttling process %d\n", (int) pid);
762            }
763            else // parent
764            {
765                execvp(argv[last_known_argument], 
766                       &(argv[last_known_argument]));
767                
768                // we should never return  
769                exit(2);
770            }
771            */
772            
773         }      // end of launching child process
774
775         if (!process_ok && !pid_ok) {
776                 fprintf(stderr,"Error: You must specify a target process\n");
777                 print_usage (stderr, 1);
778                 exit(1);
779         }
780         if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
781                 fprintf(stderr,"Error: You must specify exactly one target process\n");
782                 print_usage (stderr, 1);
783                 exit(1);
784         }
785         if (!limit_ok) {
786                 fprintf(stderr,"Error: You must specify a cpu limit\n");
787                 print_usage (stderr, 1);
788                 exit(1);
789         }
790         float limit=perclimit/100.0;
791         if ( (limit <= 0.00) || (limit > NCPU) )
792         {
793                 fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU);
794                 print_usage (stderr, 1);
795                 exit(1);
796         }
797
798         // check to see if we should fork
799         if (run_in_background)
800         {
801              pid_t process_id;
802              process_id = fork();
803              if (! process_id)
804                 exit(0);
805              else
806              {
807                 setsid();
808                 process_id = fork();
809                 if (process_id)
810                   exit(0);
811              }
812         }
813
814         //parameters are all ok!
815         signal(SIGINT,quit);
816         signal(SIGTERM,quit);
817
818         my_pid = getpid();
819         if (verbose)
820            printf("%d CPUs detected.\n", NCPU);
821
822         increase_priority();
823 /*
824 Instead of all this big block of code to detect and change
825 priority settings, let us just use the increase_priority()
826 function. It is a little more simple and takes a more
827 gradual approach, rather than "all or nothing".
828 -- Jesse
829
830         if (setpriority(PRIO_PROCESS, my_pid,-20)!=0) {
831         //if that failed, check if we have a limit 
832         // by how much we can raise the priority
833 #ifdef RLIMIT_NICE 
834 //check if non-root can even make changes 
835 // (ifdef because it's only available in linux >= 2.6.13)
836                 nice_lim=getpriority(PRIO_PROCESS, my_pid);
837                 getrlimit(RLIMIT_NICE, &maxlimit);
838
839 //if we can do better then current
840                 if( (20 - (signed)maxlimit.rlim_cur) < nice_lim &&  
841                     setpriority(PRIO_PROCESS, my_pid,
842                     20 - (signed)maxlimit.rlim_cur)==0 //and it actually works
843                   ) {
844
845                         //if we can do better, but not by much, warn about it
846                         if( (nice_lim - (20 - (signed)maxlimit.rlim_cur)) < 9) 
847                         {
848                         printf("Warning, can only increase priority by %d.\n",                                nice_lim - (20 - (signed)maxlimit.rlim_cur));
849                         }
850                         //our new limit
851                         nice_lim = 20 - (signed)maxlimit.rlim_cur; 
852
853                 } else 
854 // otherwise don't try to change priority. 
855 // The below will also run if it's not possible 
856 // for non-root to change priority
857 #endif
858                 {
859                         printf("Warning: cannot renice.\nTo work better you should run this program as root, or adjust RLIMIT_NICE.\nFor example in /etc/security/limits.conf add a line with: * - nice -10\n\n");
860                         nice_lim=INT_MAX;
861                 }
862         } else {
863                 nice_lim=-20;
864         }
865 */
866
867
868         //time quantum in microseconds. it's splitted in a working period and a sleeping one
869         int period=100000;
870         struct timespec twork,tsleep;   //working and sleeping intervals
871         memset(&twork,0,sizeof(struct timespec));
872         memset(&tsleep,0,sizeof(struct timespec));
873
874 wait_for_process:
875
876         //look for the target process..or wait for it
877         if (exe != NULL)
878                 pid=getpidof(exe);
879         else if (path != NULL)
880                 pid=getpidof(path);
881         else 
882                 waitforpid(pid);
883
884         
885         //process detected...let's play
886
887         //init compute_cpu_usage internal stuff
888         compute_cpu_usage(0,0,NULL);
889         //main loop counter
890         int i=0;
891
892         struct timespec startwork,endwork;
893         long workingtime=0;             //last working time in microseconds
894
895         if (verbose) print_caption();
896
897         float pcpu_avg=0;
898
899         //here we should already have high priority, for time precision
900         while(1) {
901
902                 //estimate how much the controlled process is using the cpu in its working interval
903                 struct cpu_usage cu;
904                 if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
905             if (!quiet)
906                         fprintf(stderr,"Process %d dead!\n",pid);
907                         if (lazy) exit(2);
908                         //wait until our process appears
909                         goto wait_for_process;          
910                 }
911
912                 //cpu actual usage of process (range 0-1)
913                 float pcpu=cu.pcpu;
914                 //rate at which we are keeping active the process (range 0-1)
915                 float workingrate=cu.workingrate;
916
917                 //adjust work and sleep time slices
918                 if (pcpu>0) {
919                         twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
920                 }
921                 else if (pcpu==0) {
922                         twork.tv_nsec=period*1000;
923                 }
924                 else if (pcpu==-1) {
925                         //not yet a valid idea of cpu usage
926                         pcpu=limit;
927                         workingrate=limit;
928                         twork.tv_nsec=min(period*limit*1000,period*1000);
929                 }
930                 tsleep.tv_nsec=period*1000-twork.tv_nsec;
931
932                 //update average usage
933                 pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
934
935                 if (verbose && i%10==0 && i>0) {
936                         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);
937                         if (i%200 == 0)
938                            print_caption();
939                 }
940
941                 // if (limit<1 && limit>0) {
942                 // printf("Comparing %f to %f\n", pcpu, limit);
943                 if (pcpu < limit)
944                 {
945                         // printf("Continue\n");
946                         //resume process
947                         if (kill(pid,SIGCONT)!=0) {
948                 if (!quiet)
949                                 fprintf(stderr,"Process %d dead!\n",pid);
950                                 if (lazy) exit(2);
951                                 //wait until our process appears
952                                 goto wait_for_process;
953                         }
954                 }
955
956                 #ifdef __APPLE_
957                 // OS X does not have clock_gettime, use clock_get_time
958                 clock_serv_t cclock;
959                 mach_timespec_t mts;
960                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
961                 clock_get_time(cclock, &mts);
962                 mach_port_deallocate(mach_task_self(), cclock);
963                 startwork.tv_sec = mts.tv_sec;
964                 startwork.tv_nsec = mts.tv_nsec;
965
966                 #else
967                 clock_gettime(CLOCK_REALTIME,&startwork);
968                 #endif
969
970                 nanosleep(&twork,NULL);         //now process is working
971                 #ifdef __APPLE__
972                 // OS X does not have clock_gettime, use clock_get_time
973                 // clock_serv_t cclock;
974                 // mach_timespec_t mts;
975                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
976                 clock_get_time(cclock, &mts);
977                 mach_port_deallocate(mach_task_self(), cclock);
978                 endwork.tv_sec = mts.tv_sec;
979                 endwork.tv_nsec = mts.tv_nsec;
980
981                 #else
982                 clock_gettime(CLOCK_REALTIME,&endwork);
983                 #endif
984                 workingtime=timediff(&endwork,&startwork);
985
986                 // if (limit<1) {
987                 // printf("Checking %f vs %f\n", pcpu, limit);
988                 if (pcpu > limit)
989                 {
990                      // When over our limit we may run into
991                      // situations where we want to kill
992                      // the offending process, then restart it
993                      if (kill_process)
994                      {
995                          kill(pid, SIGKILL);
996                          if (!quiet)
997                              fprintf(stderr, "Process %d killed.\n", pid);
998                          if ( (lazy) && (! restore_process) ) 
999                               exit(2);
1000                          // restart killed process
1001                          if (restore_process)
1002                          {
1003                              pid_t new_process;
1004                              new_process = fork();
1005                              if (new_process == -1)
1006                              {
1007                               fprintf(stderr, "Failed to restore killed process.\n");
1008                              }
1009                              else if (new_process == 0)
1010                              {
1011                                 // child which becomes new process
1012                                 if (verbose)
1013                                    printf("Relaunching %s\n",
1014                                           argv[last_known_argument]);
1015                                 execvp(argv[last_known_argument],
1016                                        &(argv[last_known_argument]) ); 
1017                              }
1018                              else // parent
1019                              {
1020                                 // we need to track new process
1021                                 pid = new_process;
1022                                 // avoid killing child process
1023                                 sleep(5);
1024                              }
1025                          }
1026                      }
1027                      // do not kll process, just throttle it
1028                      else
1029                      {
1030
1031                         // printf("Stop\n");
1032                         //stop process, it has worked enough
1033                         if (kill(pid,SIGSTOP)!=0) {
1034                 if (!quiet)
1035                                 fprintf(stderr,"Process %d dead!\n", pid);
1036                                 if (lazy) exit(2);
1037                                 //wait until our process appears
1038                                 goto wait_for_process;
1039                         }
1040                         nanosleep(&tsleep,NULL);        //now process is sleeping
1041                       }   // end of throttle process
1042                 }         // end of process using too much CPU
1043                 i++;
1044         }
1045
1046    return 0;
1047 }