New upstream release. Fixes feature request "foreground option". (Closes: #836027)
[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.3
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 // Handle a child process quitting
333 void Child_Done(int sig)
334 {
335    pid_t caught_child;
336    caught_child = waitpid(-1, NULL, WNOHANG);
337    printf("Caught child process: %d\n", (int) caught_child);
338    printf("%d\n", errno);
339    if (caught_child == pid)
340    {
341       printf("Child process is finished, exiting...\n");
342       exit(0);
343    }
344 }
345
346
347 #ifdef FREEBSD
348 //get jiffies count from /proc filesystem
349 int getjiffies(int pid)
350 {
351    kvm_t *my_kernel = NULL;
352    struct kinfo_proc *process_data = NULL;
353    int processes;
354    int my_jiffies = -1;
355
356    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
357    if (! my_kernel)
358    {
359       fprintf(stderr, "Error opening kernel vm. You should be running as root.\n");
360       return -1;
361    }
362
363    process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes);
364    if ( (process_data) && (processes >= 1) )
365        my_jiffies = process_data->ki_runtime;
366    
367    kvm_close(my_kernel);
368    if (my_jiffies >= 0)
369      my_jiffies /= 1000;
370    return my_jiffies;
371 }
372
373 #endif
374
375 #ifdef LINUX
376 int getjiffies(int pid) {
377         static char stat[20];
378         static char buffer[1024];
379         char *p;
380         sprintf(stat,"/proc/%d/stat",pid);
381         FILE *f=fopen(stat,"r");
382         if (f==NULL) return -1;
383         p = fgets(buffer,sizeof(buffer),f);
384         fclose(f);
385         // char *p=buffer;
386         if (p)
387         {
388           p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
389           int sp=12;
390           while (sp--)
391                 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
392           //user mode jiffies
393           int utime=atoi(p+1);
394           p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
395           //kernel mode jiffies
396           int ktime=atoi(p+1);
397           return utime+ktime;
398         }
399         // could not read info
400         return -1;
401 }
402 #endif
403
404
405 //process instant photo
406 struct process_screenshot {
407         struct timespec when;   //timestamp
408         int jiffies;    //jiffies count of the process
409         int cputime;    //microseconds of work from previous screenshot to current
410 };
411
412 //extracted process statistics
413 struct cpu_usage {
414         float pcpu;
415         float workingrate;
416 };
417
418 //this function is an autonomous dynamic system
419 //it works with static variables (state variables of the system), that keep memory of recent past
420 //its aim is to estimate the cpu usage of the process
421 //to work properly it should be called in a fixed periodic way
422 //perhaps i will put it in a separate thread...
423 int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
424         #define MEM_ORDER 10
425         //circular buffer containing last MEM_ORDER process screenshots
426         static struct process_screenshot ps[MEM_ORDER];
427         //the last screenshot recorded in the buffer
428         static int front=-1;
429         //the oldest screenshot recorded in the buffer
430         static int tail=0;
431
432         if (pusage==NULL) {
433                 //reinit static variables
434                 front=-1;
435                 tail=0;
436                 return 0;
437         }
438
439         //let's advance front index and save the screenshot
440         front=(front+1)%MEM_ORDER;
441         int j=getjiffies(pid);
442         if (j>=0) ps[front].jiffies=j;
443         else return -1; //error: pid does not exist
444
445         #ifdef __APPLE__
446         // OS X does not have clock_gettime, use clock_get_time
447         clock_serv_t cclock;
448         mach_timespec_t mts;
449         host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
450         clock_get_time(cclock, &mts);
451         mach_port_deallocate(mach_task_self(), cclock);
452         ps[front].when.tv_sec = mts.tv_sec;
453         ps[front].when.tv_nsec = mts.tv_nsec;
454
455         #else
456         // Linux and BSD can use real time
457         clock_gettime(CLOCK_REALTIME,&(ps[front].when));
458         ps[front].cputime=last_working_quantum;
459         #endif
460         //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
461         int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
462
463         if (size==1) {
464                 //not enough samples taken (it's the first one!), return -1
465                 pusage->pcpu=-1;
466                 pusage->workingrate=1;
467                 return 0;
468         }
469         else {
470                 //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
471                 long dt=timediff(&(ps[front].when),&(ps[tail].when));
472                 long dtwork=0;
473                 int i=(tail+1)%MEM_ORDER;
474                 int max=(front+1)%MEM_ORDER;
475                 do {
476                         dtwork+=ps[i].cputime;
477                         i=(i+1)%MEM_ORDER;
478                 } while (i!=max);
479                 int used=ps[front].jiffies-ps[tail].jiffies;
480                 float usage=(used*1000000.0/HZ)/dtwork;
481                 pusage->workingrate=1.0*dtwork/dt;
482                 pusage->pcpu=usage*pusage->workingrate;
483                 if (size==MEM_ORDER)
484                         tail=(tail+1)%MEM_ORDER;
485                 return 0;
486         }
487         #undef MEM_ORDER
488 }
489
490 void print_caption() {
491         printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
492 }
493
494
495 void increase_priority()
496 {
497         //find the best available nice value
498         int old_priority = getpriority(PRIO_PROCESS, 0);
499         int priority = old_priority;
500         while ( (setpriority(PRIO_PROCESS, 0, priority-1) == 0) &&
501                 (priority > BEST_PRIORITY) )
502         {
503                 priority--;
504         }
505         if (priority != old_priority) {
506                 if (verbose) printf("Priority changed to %d\n", priority);
507         }
508         else {
509                 if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
510         }
511
512
513 }
514
515
516
517 void print_usage(FILE *stream,int exit_code) {
518         fprintf(stream, "CPUlimit version %1.1f\n", VERSION);
519         fprintf(stream, "Usage: %s TARGET [OPTIONS...] [-- PROGRAM]\n",program_name);
520         fprintf(stream, "   TARGET must be exactly one of these:\n");
521         fprintf(stream, "      -p, --pid=N        pid of the process\n");
522         fprintf(stream, "      -e, --exe=FILE     name of the executable program file\n");
523         fprintf(stream, "                         The -e option only works when\n");
524         fprintf(stream, "                         cpulimit is run with admin rights.\n");
525         fprintf(stream, "      -P, --path=PATH    absolute path name of the\n");
526         fprintf(stream, "                         executable program file\n");
527         fprintf(stream, "   OPTIONS\n");
528         fprintf(stream, "      -b  --background   run in background\n");
529         fprintf(stream, "      -f  --foreground   launch target process in foreground and wait for it to exit\n");
530         fprintf(stream, "      -c  --cpu=N        override the detection of CPUs on the machine.\n");
531         fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
532         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
533         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
534         fprintf(stream, "      -q, --quiet        run in quiet mode (only print errors).\n");
535         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
536         fprintf(stream, "                         instead of just throttling them.\n");
537         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
538         fprintf(stream, "                         been killed. Works with the -k flag.\n");
539         fprintf(stream, "      -s, --signal=SIG   Send this signal to the watched process when cpulimit exits.\n");
540         fprintf(stream, "                         Signal should be specificed as a number or \n");
541         fprintf(stream, "                         SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.\n");
542         fprintf(stream, "      -v, --verbose      show control statistics\n");
543         fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
544         fprintf(stream, "                         or if it dies\n");
545         fprintf(stream, "          --             This is the final CPUlimit option. All following\n");
546         fprintf(stream, "                         options are for another program we will launch.\n");
547         fprintf(stream, "      -h, --help         display this help and exit\n");
548         exit(exit_code);
549 }
550
551
552
553 // Get the number of CPU cores on this machine.
554 int get_ncpu()
555 {
556         int ncpu = 1;
557 #ifdef _SC_NPROCESSORS_ONLN
558         ncpu = sysconf(_SC_NPROCESSORS_ONLN);
559 #endif
560         return ncpu;
561 }
562
563
564 // This function attempts to figure out what signal we should send
565 // target processes based on a command line paramter. First we check
566 // for text such as SIGINT, SIGCONT, SIGSTOP, etc. If no match is found
567 // then we assume the value given is a number and use that.
568 int Translate_Signal(char *my_signal)
569 {
570     int signal_value;
571     int index = 0, found = FALSE;
572     // first check to see if we were passed a string
573     while ( (index < MAX_SIGNAL) && (! found) )
574     {
575         if (! strcmp(my_signal, SIGNAL_NAME[index]) )
576         {
577             found = TRUE;
578             signal_value = SIGNAL_VALUE[index];
579         }
580         else
581            index++;
582     }
583
584     // no value found, try a number
585     if (! found)
586        signal_value = atoi(my_signal);
587
588     return signal_value;
589 }
590
591
592
593 int main(int argc, char **argv) {
594
595         //get program name
596         // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
597         // program_name = p==NULL?argv[0]:(p+1);
598         program_name = argv[0];
599         int run_in_background = FALSE;
600         //parse arguments
601         int next_option;
602         /* A string listing valid short options letters. */
603         const char* short_options="p:e:P:l:c:s:bfqkrvzh";
604         /* An array describing valid long options. */
605         const struct option long_options[] = {
606                 { "pid", required_argument, NULL, 'p' },
607                 { "exe", required_argument, NULL, 'e' },
608                 { "path", required_argument, NULL, 'P' },
609                 { "limit", required_argument, NULL, 'l' },
610                 { "background", no_argument, NULL, 'b' },
611                 { "foreground", no_argument, NULL, 'f' },
612                 { "quiet", no_argument, NULL, 'q' },
613                 { "verbose", no_argument, NULL, 'v' },
614                 { "lazy", no_argument, NULL, 'z' },
615                 { "help", no_argument, NULL, 'h' },
616                 { "cpu", required_argument, NULL, 'c'},
617                 { "signal", required_argument, NULL, 's'},
618                 { NULL, 0, NULL, 0 }
619         };
620         //argument variables
621         const char *exe=NULL;
622         const char *path=NULL;
623         int perclimit=0;
624         int pid_ok = FALSE;
625         int process_ok = FALSE;
626         int limit_ok = FALSE;
627         int last_known_argument = 0;
628         int kill_process = FALSE;   // kill process instead of stopping it
629         int restore_process = FALSE;  // restore killed process
630         int run_child_in_background = TRUE;  // run cpulimit in background when 
631                                              //  we launch new process
632         // struct rlimit maxlimit;
633
634         NCPU = get_ncpu();
635
636         opterr = 0;      // avoid unwanted error messages for unknown parameters
637         do {
638                 next_option = getopt_long (argc, argv, short_options,long_options, NULL);
639                 switch(next_option) {
640                         case 'b':
641                                 run_in_background = TRUE;
642                                 last_known_argument++;
643                                 break;
644                         case 'f':
645                                 run_child_in_background = FALSE;
646                                 run_in_background = FALSE;
647                                 last_known_argument++;
648                                 break;
649                         case 'p':
650                                 pid=atoi(optarg);
651                                 if (pid)   // valid PID
652                                 {
653                                   pid_ok = TRUE;
654                                   lazy = TRUE;
655                                 }
656                                 last_known_argument += 2;
657                                 break;
658                         case 'e':
659                                 exe=optarg;
660                                 process_ok = TRUE;
661                                 last_known_argument += 2;
662                                 break;
663                         case 'P':
664                                 path=optarg;
665                                 process_ok = TRUE;
666                                 last_known_argument += 2;
667                                 break;
668                         case 'l':
669                                 perclimit=atoi(optarg);
670                                 limit_ok = TRUE;
671                                 last_known_argument += 2;
672                                 break;
673                         case 'c':
674                                 NCPU = atoi(optarg);
675                                 last_known_argument += 2;
676                                 break;
677                         case 's':
678                                 send_signal = Translate_Signal(optarg);
679                                 if ( (send_signal < 1) || (send_signal > 35) )
680                                 {
681                                     fprintf(stderr, "Specified exit signal is not recognized or not within bounds (1-35). Using SIGCONT.\n");
682                                     send_signal = SIGCONT;
683                                 }
684                                 last_known_argument += 2;
685                         case 'k':
686                                 kill_process = TRUE;
687                                 last_known_argument++;
688                                 break;
689                         case 'r':
690                                 restore_process = TRUE;
691                                 last_known_argument++;
692                                 break;
693
694                         case 'v':
695                                 verbose = TRUE;
696                                 last_known_argument++;
697                                 break;
698                         case 'q':
699                                 quiet = TRUE;
700                                 last_known_argument++;
701                                 break;
702                         case 'z':
703                                 lazy = TRUE;
704                                 last_known_argument++;
705                                 break;
706                         case 'h':
707                                 print_usage (stdout, 1);
708                                 last_known_argument++;
709                                 break;
710                         case 'o':
711                                 last_known_argument++;
712                                 next_option = -1;
713                                 break;
714                         case '?':
715                                 print_usage (stderr, 1);
716                                 last_known_argument++;
717                                 break;
718                         case -1:
719                                 break;
720                         // default:
721                         //      abort();
722                 }
723         } while(next_option != -1);
724
725         signal(SIGCHLD, Child_Done);
726
727         // try to launch a program passed on the command line
728         // But only if we do not already have a PID to watch
729         if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) )
730         {
731            last_known_argument++;
732            // if we stopped on "--" jump to the next parameter
733            if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) )
734                last_known_argument++;
735            pid_t forked_pid;
736            // try to launch remaining arguments
737            if (verbose)
738            {
739                int index = last_known_argument;
740                printf("Launching %s", argv[index]);
741                for (index = last_known_argument + 1; index < argc; index++)
742                     printf(" %s", argv[index]);
743                printf(" with limit %d\n", perclimit);
744            }
745            forked_pid = fork();
746            if (forked_pid == -1)  // error
747            {
748                printf("Failed to launch specified process.\n");
749                exit(1);
750            }
751            else if (forked_pid == 0)   // target child
752            {
753               execvp(argv[last_known_argument],
754                      &(argv[last_known_argument]) );
755               exit(2);
756            }
757            else     // parent who will now fork the throttler
758            {
759               pid_t limit_pid;
760               // if we are planning to kill a process, give it
761               // a running head start to avoid death at start-up
762               if (kill_process)
763                  sleep(5);
764     
765               /* The following block assumes we want to run cpulimit in the
766                  background. This is the default behaviour.
767               */ 
768               if (run_child_in_background)
769               {
770                  limit_pid = fork();
771                  if (limit_pid == 0)   // child cpulimit process running in background
772                  {
773                     pid = forked_pid;    // the first child, target process
774                     lazy = TRUE;
775                     pid_ok = TRUE;
776                     if (verbose)
777                       printf("Throttling process %d\n", (int) pid);
778                  }
779                  else    // parent cpulimit process which can quit
780                    exit(0);
781               }  // end of running in background
782               else
783               {
784                   pid = forked_pid;
785                   lazy = TRUE;
786                   pid_ok = TRUE;
787                   run_in_background = FALSE;
788               }  // end of running in foreground
789
790            }  // end of parent that launched target
791
792         }      // end of launching child process
793
794         if (!process_ok && !pid_ok) {
795                 fprintf(stderr,"Error: You must specify a target process\n");
796                 print_usage (stderr, 1);
797                 exit(1);
798         }
799         if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
800                 fprintf(stderr,"Error: You must specify exactly one target process\n");
801                 print_usage (stderr, 1);
802                 exit(1);
803         }
804         if (!limit_ok) {
805                 fprintf(stderr,"Error: You must specify a cpu limit\n");
806                 print_usage (stderr, 1);
807                 exit(1);
808         }
809         float limit=perclimit/100.0;
810         if ( (limit <= 0.00) || (limit > NCPU) )
811         {
812                 fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU);
813                 print_usage (stderr, 1);
814                 exit(1);
815         }
816
817         // check to see if we should fork
818         if (run_in_background)
819         {
820              pid_t process_id;
821              process_id = fork();
822              if (! process_id)
823                 exit(0);
824              else
825              {
826                 setsid();
827                 process_id = fork();
828                 if (process_id)
829                   exit(0);
830              }
831         }
832
833         //parameters are all ok!
834         signal(SIGINT,quit);
835         signal(SIGTERM,quit);
836
837         my_pid = getpid();
838         if (verbose)
839            printf("%d CPUs detected.\n", NCPU);
840
841         increase_priority();
842
843         //time quantum in microseconds. it's splitted in a working period and a sleeping one
844         int period=100000;
845         struct timespec twork,tsleep;   //working and sleeping intervals
846         memset(&twork,0,sizeof(struct timespec));
847         memset(&tsleep,0,sizeof(struct timespec));
848
849 wait_for_process:
850
851         //look for the target process..or wait for it
852         if (exe != NULL)
853                 pid=getpidof(exe);
854         else if (path != NULL)
855                 pid=getpidof(path);
856         else 
857                 waitforpid(pid);
858
859         
860         //process detected...let's play
861
862         //init compute_cpu_usage internal stuff
863         compute_cpu_usage(0,0,NULL);
864         //main loop counter
865         int i=0;
866
867         struct timespec startwork,endwork;
868         long workingtime=0;             //last working time in microseconds
869
870         if (verbose) print_caption();
871
872         float pcpu_avg=0;
873
874         //here we should already have high priority, for time precision
875         while(1) {
876
877                 //estimate how much the controlled process is using the cpu in its working interval
878                 struct cpu_usage cu;
879                 if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
880             if (!quiet)
881                         fprintf(stderr,"Process %d dead!\n",pid);
882                         if (lazy) exit(2);
883                         //wait until our process appears
884                         goto wait_for_process;          
885                 }
886
887                 //cpu actual usage of process (range 0-1)
888                 float pcpu=cu.pcpu;
889                 //rate at which we are keeping active the process (range 0-1)
890                 float workingrate=cu.workingrate;
891
892                 //adjust work and sleep time slices
893                 if (pcpu>0) {
894                         twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
895                 }
896                 else if (pcpu==0) {
897                         twork.tv_nsec=period*1000;
898                 }
899                 else if (pcpu==-1) {
900                         //not yet a valid idea of cpu usage
901                         pcpu=limit;
902                         workingrate=limit;
903                         twork.tv_nsec=min(period*limit*1000,period*1000);
904                 }
905                 tsleep.tv_nsec=period*1000-twork.tv_nsec;
906
907                 //update average usage
908                 pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
909
910                 if (verbose && i%10==0 && i>0) {
911                         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);
912                         if (i%200 == 0)
913                            print_caption();
914                 }
915
916                 // if (limit<1 && limit>0) {
917                 // printf("Comparing %f to %f\n", pcpu, limit);
918                 if (pcpu < limit)
919                 {
920                         // printf("Continue\n");
921                         //resume process
922                         if (kill(pid,SIGCONT)!=0) {
923                              if (!quiet)
924                                 fprintf(stderr,"Process %d dead!\n",pid);
925                              if (lazy) exit(2);
926                                 //wait until our process appears
927                                 goto wait_for_process;
928                         }
929                 }
930
931                 #ifdef __APPLE_
932                 // OS X does not have clock_gettime, use clock_get_time
933                 clock_serv_t cclock;
934                 mach_timespec_t mts;
935                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
936                 clock_get_time(cclock, &mts);
937                 mach_port_deallocate(mach_task_self(), cclock);
938                 startwork.tv_sec = mts.tv_sec;
939                 startwork.tv_nsec = mts.tv_nsec;
940
941                 #else
942                 clock_gettime(CLOCK_REALTIME,&startwork);
943                 #endif
944
945                 nanosleep(&twork,NULL);         //now process is working
946                 #ifdef __APPLE__
947                 // OS X does not have clock_gettime, use clock_get_time
948                 // clock_serv_t cclock;
949                 // mach_timespec_t mts;
950                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
951                 clock_get_time(cclock, &mts);
952                 mach_port_deallocate(mach_task_self(), cclock);
953                 endwork.tv_sec = mts.tv_sec;
954                 endwork.tv_nsec = mts.tv_nsec;
955
956                 #else
957                 clock_gettime(CLOCK_REALTIME,&endwork);
958                 #endif
959                 workingtime=timediff(&endwork,&startwork);
960
961                 // if (limit<1) {
962                 // printf("Checking %f vs %f\n", pcpu, limit);
963                 if (pcpu > limit)
964                 {
965                      // When over our limit we may run into
966                      // situations where we want to kill
967                      // the offending process, then restart it
968                      if (kill_process)
969                      {
970                          kill(pid, SIGKILL);
971                          if (!quiet)
972                              fprintf(stderr, "Process %d killed.\n", pid);
973                          if ( (lazy) && (! restore_process) ) 
974                               exit(2);
975                          // restart killed process
976                          if (restore_process)
977                          {
978                              pid_t new_process;
979                              new_process = fork();
980                              if (new_process == -1)
981                              {
982                               fprintf(stderr, "Failed to restore killed process.\n");
983                              }
984                              else if (new_process == 0)
985                              {
986                                 // child which becomes new process
987                                 if (verbose)
988                                    printf("Relaunching %s\n",
989                                           argv[last_known_argument]);
990                                 execvp(argv[last_known_argument],
991                                        &(argv[last_known_argument]) ); 
992                              }
993                              else // parent
994                              {
995                                 // we need to track new process
996                                 pid = new_process;
997                                 // avoid killing child process
998                                 sleep(5);
999                              }
1000                          }
1001                      }
1002                      // do not kill process, just throttle it
1003                      else
1004                      {
1005
1006                         // printf("Stop\n");
1007                         //stop process, it has worked enough
1008                         if (kill(pid,SIGSTOP)!=0) {
1009                             if (!quiet)
1010                                 fprintf(stderr,"Process %d dead!\n", pid);
1011                             if (lazy) exit(2);
1012                                 //wait until our process appears
1013                                 goto wait_for_process;
1014                         }
1015                         nanosleep(&tsleep,NULL);        //now process is sleeping
1016                       }   // end of throttle process
1017                 }         // end of process using too much CPU
1018                 i++;
1019         }
1020
1021    return 0;
1022 }