releasing package cpulimit version 2.8-1 into distribution unstable
[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 #ifdef LINUX
60 #include <dirent.h>
61 #define PROC_FILENAME 512
62 #define LINE_LENGTH 256
63 #endif
64
65 //kernel time resolution (inverse of one jiffy interval) in Hertz
66 //i don't know how to detect it, then define to the default (not very clean!)
67 #define HZ 100
68
69 //some useful macro
70 #define min(a,b) (a<b?a:b)
71 #define max(a,b) (a>b?a:b)
72
73 // For platforms without PATH_MAX
74 #ifndef PATH_MAX
75 #define PATH_MAX 4096
76 #endif
77 #ifndef EXEC_PATH
78 #define EXEC_PATH 32
79 #endif
80
81 #define BEST_PRIORITY -10
82
83 #ifndef TRUE
84 #define TRUE 1
85 #endif
86 #ifndef FALSE
87 #define FALSE 0
88 #endif
89
90 #ifndef VERSION
91 #define VERSION 0.0
92 #endif
93
94 //pid of the controlled process
95 pid_t pid = 0;
96 pid_t my_pid;     // this process's PID
97
98 //executable file name
99 char *program_name;
100 //verbose mode
101 int verbose = FALSE;
102 //lazy mode
103 int lazy = FALSE;
104 // is higher priority nice possible?
105 int nice_lim;
106
107 // number of CPUs we detected
108 int NCPU;
109
110 // quiet mode
111 int quiet = FALSE;
112
113 // What signal should we send to the watched process
114 // when cpulimit exits?
115 int send_signal = SIGCONT;
116
117 //reverse byte search
118 // void *memrchr(const void *s, int c, size_t n);
119
120 #define MAX_SIGNAL 7
121 const char *SIGNAL_NAME[MAX_SIGNAL] = { "SIGHUP", "SIGINT", "SIGQUIT", 
122                                  "SIGKILL", "SIGTERM", "SIGSTOP", "SIGCONT" };
123 const int SIGNAL_VALUE[MAX_SIGNAL] = { SIGHUP, SIGINT, SIGQUIT,
124                                   SIGKILL, SIGTERM, SIGSTOP, SIGCONT };
125
126
127 //return ta-tb in microseconds (no overflow checks!)
128 inline long timediff(const struct timespec *ta,const struct timespec *tb) {
129     unsigned long us = (ta->tv_sec-tb->tv_sec)*1000000 + (ta->tv_nsec/1000 - tb->tv_nsec/1000);
130     return us;
131 }
132
133
134 #ifdef LINUX
135 #include <pthread.h>
136
137 typedef struct
138 {
139    pid_t child;   // the child of our target process
140    pid_t monitor; // the LimitCPU fork monitoring the child
141    void *next; 
142 } CHILD;
143
144 int quitting = FALSE;           // Have we receive a quit signal
145 int monitor_children = FALSE;   // are we monitoring children of target
146
147 // Data passed to the monitor thread
148 typedef struct
149 {
150    int limit;           // per cent limit to place on a process
151    char *this_program;  // copy of argv[0]
152 } PROGRAM_DATA;
153
154 #endif
155
156
157
158 int Check_Us(pid_t target_pid)
159 {
160    pid_t this_pid;
161
162    this_pid = getpid();
163    if (this_pid == target_pid)
164    {
165       fprintf(stderr, "We cannot throttle ourselves.\n");
166       exit(7);
167    }
168    return TRUE;
169 }
170
171
172 int waitforpid(int pid) {
173         //switch to low priority
174         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
175         /*
176         if ( (nice_lim < INT_MAX) && 
177              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
178                 printf("Warning: cannot renice\n");
179         }
180         */
181         int i=0;
182
183         while(1) {
184
185                 DIR *dip;
186                 struct dirent *dit;
187
188                 //open a directory stream to /proc directory
189                 if ((dip = opendir("/proc")) == NULL) {
190                         perror("opendir");
191                         return -1;
192                 }
193
194                 //read in from /proc and seek for process dirs
195                 while ((dit = readdir(dip)) != NULL) {
196                         //get pid
197                         if (pid==atoi(dit->d_name)) {
198                                 //pid detected
199                                 Check_Us(pid);
200                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
201                                         //process is ok!
202                                         if (closedir(dip) == -1) {
203                                            perror("closedir");
204                                            return -1;
205                                         }
206                                         goto done;
207                                 }
208                                 else {
209                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
210                                 }
211                         }
212                 }
213
214                 //close the dir stream and check for errors
215                 if (closedir(dip) == -1) {
216                         perror("closedir");
217                         return -1;
218                 }
219
220                 //no suitable target found
221                 if (i++==0) {
222                         if (lazy) {
223                                 fprintf(stderr,"No process found\n");
224                                 exit(2);
225                         }
226                         else {
227                                 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
228                         }
229                 }
230
231                 //sleep for a while
232                 sleep(2);
233         }
234
235 done:
236     if (!quiet)
237         printf("Process %d detected\n",pid);
238
239     //now set high priority, if possible
240     // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
241     /*
242     if ( (nice_lim < INT_MAX) &&
243          (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
244        printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
245     }
246     */
247     return 0;
248
249 }
250
251 //this function periodically scans process list and looks for executable path names
252 //it should be executed in a low priority context, since precise timing does not matter
253 //if a process is found then its pid is returned
254 //process: the name of the wanted process, can be an absolute path name to the executable file
255 //         or simply its name
256 //return: pid of the found process
257 int getpidof(const char *process) {
258
259         //set low priority
260         // if (setpriority(PRIO_PROCESS,getpid(),19)!=0) {
261         /*
262         if ( (nice_lim < INT_MAX) &&
263              (setpriority(PRIO_PROCESS, my_pid, 19) != 0) ) {
264                 printf("Warning: cannot renice\n");
265         }
266         */
267         char exelink[EXEC_PATH + 1];
268         char exepath[PATH_MAX+1];
269         int pid=0;
270         int i=0;
271
272         while(1) {
273
274                 DIR *dip;
275                 struct dirent *dit;
276
277                 //open a directory stream to /proc directory
278                 if ((dip = opendir("/proc")) == NULL) {
279                         perror("opendir");
280                         return -1;
281                 }
282
283                 //read in from /proc and seek for process dirs
284                 while ((dit = readdir(dip)) != NULL) {
285                         //get pid
286                         pid=atoi(dit->d_name);
287                         if (pid>0) {
288                                 snprintf(exelink, EXEC_PATH, "/proc/%d/exe",pid);
289                                 int size=readlink(exelink,exepath,sizeof(exepath));
290                                 if (size>0) {
291                                         int found=0;
292                                         if (process[0]=='/' && strncmp(exepath,process,size)==0 && size==strlen(process)) {
293                                                 //process starts with / then it's an absolute path
294                                                 found=1;
295                                         }
296                                         else {
297                                                 //process is the name of the executable file
298                                                 if (strncmp(exepath+size-strlen(process),process,strlen(process))==0) {
299                                                         found=1;
300                                                 }
301                                         }
302                                         if (found==1) {
303                                         Check_Us(pid);
304                                                 if (kill(pid,SIGSTOP)==0 &&  kill(pid,SIGCONT)==0) {
305                                                         //process is ok!
306                                                         if (closedir(dip) == -1) {
307                                                           perror("closedir");
308                                                           return -1;
309                                                         }
310                                                         goto done;
311                                                 }
312                                                 else {
313                                                         fprintf(stderr,"Error: Process %d detected, but you don't have permission to control it\n",pid);
314                                                 }
315                                         }
316                                 }
317                         }
318                 }
319
320                 //close the dir stream and check for errors
321                 if (closedir(dip) == -1) {
322                         perror("closedir");
323                         return -1;
324                 }
325
326                 //no suitable target found
327                 if (i++==0) {
328                         if (lazy) {
329                                 fprintf(stderr,"No process found\n");
330                                 exit(2);
331                         }
332                         else {
333                                 fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
334                         }
335                 }
336
337                 //sleep for a while
338                 sleep(2);
339         }
340
341 done:
342     if (!quiet)
343         printf("Process %d detected\n",pid);
344
345     //now set high priority, if possible
346     // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
347     /*
348     if ( (nice_lim < INT_MAX) &&
349          (setpriority(PRIO_PROCESS, my_pid, nice_lim) != 0) ) {
350        printf("Warning: cannot renice.\nTo work better you should run this program as root.\n");
351     }
352     */
353     return pid;
354 }
355
356 //SIGINT and SIGTERM signal handler
357 void quit(int sig) {
358         //let the process continue if we are stopped
359         kill(pid, send_signal);
360         #ifdef LINUX
361         if (monitor_children)
362         {
363             quitting = TRUE;
364             printf("Asking children to quit...\n");
365             sleep(2);                // wait for thread clean-up
366         }
367         #endif
368         printf("Exiting...\n");
369         exit(0);
370 }
371
372 // Handle a child process quitting
373 void Child_Done(int sig)
374 {
375    pid_t caught_child;
376    caught_child = waitpid(-1, NULL, WNOHANG);
377    if (verbose)
378    {
379       printf("Caught child process: %d\n", (int) caught_child);
380       printf("%d\n", errno);
381    }
382    // If this was the one process we were watching, we can quit now.
383    if (caught_child == pid)
384    {
385       if (verbose)
386          printf("Child process is finished, exiting...\n");
387       exit(0);
388    }
389 }
390
391
392 #ifdef FREEBSD
393 int getjiffies(int pid)
394 {
395    kvm_t *my_kernel = NULL;
396    struct kinfo_proc *process_data = NULL;
397    int processes;
398    int my_jiffies = -1;
399
400    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
401    if (! my_kernel)
402    {
403       fprintf(stderr, "Error opening kernel vm. You should be running as root.\n");
404       return -1;
405    }
406
407    process_data = kvm_getprocs(my_kernel, KERN_PROC_PID, pid, &processes);
408    if ( (process_data) && (processes >= 1) )
409        my_jiffies = process_data->ki_runtime;
410    
411    kvm_close(my_kernel);
412    if (my_jiffies >= 0)
413      my_jiffies /= 1000;
414    return my_jiffies;
415 }
416
417 #endif
418
419 #ifdef LINUX
420 //get jiffies count from /proc filesystem
421 int getjiffies(int pid) {
422         static char stat[20];
423         static char buffer[1024];
424         char *p;
425         sprintf(stat,"/proc/%d/stat",pid);
426         FILE *f=fopen(stat,"r");
427         if (f==NULL) return -1;
428         p = fgets(buffer,sizeof(buffer),f);
429         fclose(f);
430         // char *p=buffer;
431         if (p)
432         {
433           p=memchr(p+1,')',sizeof(buffer)-(p-buffer));
434           int sp=12;
435           while (sp--)
436                 p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
437           //user mode jiffies
438           int utime=atoi(p+1);
439           p=memchr(p+1,' ',sizeof(buffer)-(p-buffer));
440           //kernel mode jiffies
441           int ktime=atoi(p+1);
442           return utime+ktime;
443         }
444         // could not read info
445         return -1;
446 }
447 #endif
448
449
450 //process instant photo
451 struct process_screenshot {
452         struct timespec when;   //timestamp
453         int jiffies;    //jiffies count of the process
454         int cputime;    //microseconds of work from previous screenshot to current
455 };
456
457 //extracted process statistics
458 struct cpu_usage {
459         float pcpu;
460         float workingrate;
461 };
462
463 //this function is an autonomous dynamic system
464 //it works with static variables (state variables of the system), that keep memory of recent past
465 //its aim is to estimate the cpu usage of the process
466 //to work properly it should be called in a fixed periodic way
467 //perhaps i will put it in a separate thread...
468 int compute_cpu_usage(int pid,int last_working_quantum,struct cpu_usage *pusage) {
469         #define MEM_ORDER 10
470         //circular buffer containing last MEM_ORDER process screenshots
471         static struct process_screenshot ps[MEM_ORDER];
472         //the last screenshot recorded in the buffer
473         static int front=-1;
474         //the oldest screenshot recorded in the buffer
475         static int tail=0;
476
477         if (pusage==NULL) {
478                 //reinit static variables
479                 front=-1;
480                 tail=0;
481                 return 0;
482         }
483
484         //let's advance front index and save the screenshot
485         front=(front+1)%MEM_ORDER;
486         int j=getjiffies(pid);
487         if (j>=0) ps[front].jiffies=j;
488         else return -1; //error: pid does not exist
489
490         #ifdef __APPLE__
491         // OS X does not have clock_gettime, use clock_get_time
492         clock_serv_t cclock;
493         mach_timespec_t mts;
494         host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
495         clock_get_time(cclock, &mts);
496         mach_port_deallocate(mach_task_self(), cclock);
497         ps[front].when.tv_sec = mts.tv_sec;
498         ps[front].when.tv_nsec = mts.tv_nsec;
499
500         #else
501         // Linux and BSD can use real time
502         clock_gettime(CLOCK_REALTIME,&(ps[front].when));
503         ps[front].cputime=last_working_quantum;
504         #endif
505         //buffer actual size is: (front-tail+MEM_ORDER)%MEM_ORDER+1
506         int size=(front-tail+MEM_ORDER)%MEM_ORDER+1;
507
508         if (size==1) {
509                 //not enough samples taken (it's the first one!), return -1
510                 pusage->pcpu=-1;
511                 pusage->workingrate=1;
512                 return 0;
513         }
514         else {
515                 //now we can calculate cpu usage, interval dt and dtwork are expressed in microseconds
516                 long dt=timediff(&(ps[front].when),&(ps[tail].when));
517                 long dtwork=0;
518                 int i=(tail+1)%MEM_ORDER;
519                 int max=(front+1)%MEM_ORDER;
520                 do {
521                         dtwork+=ps[i].cputime;
522                         i=(i+1)%MEM_ORDER;
523                 } while (i!=max);
524                 int used=ps[front].jiffies-ps[tail].jiffies;
525                 float usage=(used*1000000.0/HZ)/dtwork;
526                 pusage->workingrate=1.0*dtwork/dt;
527                 pusage->pcpu=usage*pusage->workingrate;
528                 if (size==MEM_ORDER)
529                         tail=(tail+1)%MEM_ORDER;
530                 return 0;
531         }
532         #undef MEM_ORDER
533 }
534
535 void print_caption() {
536         printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
537 }
538
539
540 void increase_priority()
541 {
542         //find the best available nice value
543         int old_priority = getpriority(PRIO_PROCESS, 0);
544         int priority = old_priority;
545         while ( (setpriority(PRIO_PROCESS, 0, priority-1) == 0) &&
546                 (priority > BEST_PRIORITY) )
547         {
548                 priority--;
549         }
550         if (priority != old_priority) {
551                 if (verbose) printf("Priority changed to %d\n", priority);
552         }
553         else {
554                 if (verbose) printf("Warning: Cannot change priority. Run as root or renice for best results.\n");
555         }
556
557
558 }
559
560
561
562 #ifdef LINUX
563 // This following functions are for detecting and limiting child
564 // processes on Linux.
565
566 // This function adds a new child process to our list of child processes.
567 CHILD *Add_Child(CHILD *all_children, pid_t new_pid)
568 {
569     CHILD *new_child = (CHILD *) calloc(sizeof(CHILD), 1);
570     CHILD *current;
571
572     if (! new_child)
573        return all_children;
574
575     new_child->next = NULL;
576     new_child->child = new_pid;
577     new_child->monitor = 0;
578
579     if (all_children)
580     {
581         current = all_children;
582         while (current->next)
583            current = current->next;
584         current->next = new_child;
585         return all_children;
586     }
587     else   // this is the first node
588        return new_child;
589 }
590
591
592
593 // This function removes a child PID node.
594 CHILD *Remove_Child(CHILD *all_children, pid_t old_pid)
595 {
596     CHILD *current, *previous = NULL;
597     int found = FALSE;
598
599     current = all_children;
600     while ( (! found) && (current) )
601     {
602         if (current->child == old_pid)
603         {
604            if (previous)
605                previous->next = current->next;
606            else
607              all_children = current->next;
608            
609            free(current);
610            found = TRUE;
611         }
612         else
613         {
614             previous = current;
615             current = current->next;
616         }
617      }
618      return all_children;
619 }
620
621
622 // This function cleans up all remaining child nodes.
623 void Clean_Up_Children(CHILD *all_children)
624 {
625    CHILD *current, *next;
626
627    current = all_children;
628    while (current)
629    {
630       next = current->next;
631       free(current);
632       current = next;
633    }
634 }
635
636
637 // This function searches the linked list for a matching PID.
638 // It returns NULL if no match is found and a pointer to the
639 // node is a match is located.
640 CHILD *Find_Child(CHILD *children, pid_t target)
641 {
642    CHILD *current;
643    int found = FALSE;
644
645    current = children;
646    while ( (!found) && (current) )
647    {
648       if (current->child == target)
649         found = TRUE;
650       else
651         current = current->next;
652    }
653    return current;
654 }
655
656
657
658 // This function returns a list of process IDs of children
659 // of the given process (PID). It does this by searching the /proc
660 // file system and looking in the /proc/pid/status file for the PPid field.
661 // A linked list of child PIDs is returned on success or NULL on failure or
662 // if no child PIDs are found.
663 CHILD *Find_Child_PIDs(CHILD *all_children, pid_t parent_pid)
664 {
665     int found = FALSE;
666     DIR *proc;
667     struct dirent *proc_entry;
668     char filename[PROC_FILENAME + 1];
669     FILE *status_file;
670     char *reading_file;
671     char line[256];
672     pid_t new_ppid;
673     int current_pid;
674
675     proc = opendir("/proc");
676     if (! proc)
677        return all_children;
678
679     proc_entry = readdir(proc);
680     while (proc_entry)
681     {
682         snprintf(filename, PROC_FILENAME, "/proc/%s/status", proc_entry->d_name);
683         status_file = fopen(filename, "r");
684         if (status_file)
685         {
686            found = FALSE;
687            reading_file = fgets(line, LINE_LENGTH, status_file);
688            while ( (! found) && (reading_file) )
689            {
690              if (! strncmp(line, "PPid:", 5) )
691              {
692                  sscanf(&(line[6]), "%d", &new_ppid);
693                  if (new_ppid == parent_pid && current_pid != getpid() )
694                  {
695                      sscanf(proc_entry->d_name, "%d", &current_pid);
696                      if (! Find_Child(all_children, current_pid) )
697                         all_children = Add_Child(all_children, current_pid);
698                  }
699                  found = TRUE;
700              }
701              else
702                 reading_file = fgets(line, LINE_LENGTH, status_file);
703            }   // done reading status file
704           
705            fclose(status_file);
706         }
707         proc_entry = readdir(proc);
708     }   // done reading proc file system
709     closedir(proc);
710     return all_children;
711 }
712
713
714 // This function (which should probably be called as a thread) monitors the
715 // system for child processes of the current target process. When a new
716 // child of the target is located, it is added to the CHILD list.
717 // New children result in a new fork of this program being spawned to
718 // monitor the child process and its children.
719
720 void *Monitor_Children(void *all_data)
721 {
722    CHILD *all_children = NULL;
723    CHILD *current;
724    PROGRAM_DATA *program_data = (PROGRAM_DATA *) all_data;
725
726    while (! quitting )
727    {
728       // Check for new child processes
729       all_children = Find_Child_PIDs(all_children, pid);
730
731       // Find any children without monitors and create a monitoring process
732       // Clean out old processes while we are looking
733       current = all_children;
734       while (current)
735       {
736          // First see if the child process is still running. If not,
737          // we can remote its node.
738          if (current->child)
739          {
740              char filename[PROC_FILENAME + 1];
741              DIR *child_directory;
742              snprintf(filename, PROC_FILENAME, "/proc/%d", current->child);
743              child_directory = opendir(filename);
744              if (child_directory)
745                 closedir(child_directory);
746              else
747              {
748                 if (verbose)
749                   printf("Child process %d done, cleaning up.\n",
750                           (int) current->child);
751                 all_children = Remove_Child(all_children, current->child);
752              }
753          }  // end of clean up children processes no longer running
754
755          // The child process is still running, but it might not have
756          // a monitor. Create a new monitoring process.
757          if ( (current->child) && (! current->monitor) )
758          {
759               pid_t returned_pid;
760
761               if (verbose)
762                  printf("Creating monitoring process for %d\n",
763                         (int) current->child);
764
765               returned_pid = fork();
766               if (returned_pid > 0)
767               {
768                  // parent
769                  current->monitor = returned_pid;
770               }
771               else if (returned_pid == 0)
772               {
773                  // child
774                  char limit_amount[16];
775                  char process_identifier[16];
776                  snprintf(limit_amount, 16, "%d", (int) program_data->limit);
777                  snprintf(process_identifier, 16, "%d", current->child);
778                  if (verbose)
779                     printf("Starting monitor with: %s -l %s -p %s -z -m\n",
780                             program_data->this_program, limit_amount,
781                             process_identifier);
782                  execl(program_data->this_program, program_data->this_program,
783                        "-l", limit_amount, "-p", process_identifier, 
784                        "-z", "-m", (char *) NULL);
785               }
786               
787          }    // end of creating a new monitor
788          if (verbose)
789          {
790              printf("Watching child: %d with %d\n", 
791                    (int) current->child, (int) current->monitor);
792          }
793          current = current->next;
794       }
795       sleep(1);
796    }  // end LimitCPU is still running
797    pthread_exit(NULL);
798 }
799
800 #endif       // end of monitoring children processes on Linux
801
802
803
804 void print_usage(FILE *stream,int exit_code) {
805         fprintf(stream, "CPUlimit version %1.1f\n", VERSION);
806         fprintf(stream, "Usage: %s TARGET [OPTIONS...] [-- PROGRAM]\n",program_name);
807         fprintf(stream, "   TARGET must be exactly one of these:\n");
808         fprintf(stream, "      -p, --pid=N        pid of the process\n");
809         fprintf(stream, "      -e, --exe=FILE     name of the executable program file\n");
810         fprintf(stream, "                         The -e option only works when\n");
811         fprintf(stream, "                         cpulimit is run with admin rights.\n");
812         fprintf(stream, "      -P, --path=PATH    absolute path name of the\n");
813         fprintf(stream, "                         executable program file\n");
814         fprintf(stream, "   OPTIONS\n");
815         fprintf(stream, "      -b  --background   run in background\n");
816         fprintf(stream, "      -f  --foreground   launch target process in foreground and wait for it to exit\n");
817         fprintf(stream, "      -c  --cpu=N        override the detection of CPUs on the machine.\n");
818         fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
819         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
820         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
821         #ifdef LINUX
822         fprintf(stream, "      -m, --monitor-forks  Watch children/forks of the target process\n");
823         #endif
824         fprintf(stream, "      -q, --quiet        run in quiet mode (only print errors).\n");
825         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
826         fprintf(stream, "                         instead of just throttling them.\n");
827         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
828         fprintf(stream, "                         been killed. Works with the -k flag.\n");
829         fprintf(stream, "      -s, --signal=SIG   Send this signal to the watched process when cpulimit exits.\n");
830         fprintf(stream, "                         Signal should be specificed as a number or \n");
831         fprintf(stream, "                         SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.\n");
832         fprintf(stream, "      -v, --verbose      show control statistics\n");
833         fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
834         fprintf(stream, "                         or if it dies\n");
835         fprintf(stream, "          --             This is the final CPUlimit option. All following\n");
836         fprintf(stream, "                         options are for another program we will launch.\n");
837         fprintf(stream, "      -h, --help         display this help and exit\n");
838         exit(exit_code);
839 }
840
841
842
843 // Get the number of CPU cores on this machine.
844 int get_ncpu()
845 {
846         int ncpu = 1;
847 #ifdef _SC_NPROCESSORS_ONLN
848         ncpu = sysconf(_SC_NPROCESSORS_ONLN);
849 #endif
850         return ncpu;
851 }
852
853
854 // This function attempts to figure out what signal we should send
855 // target processes based on a command line paramter. First we check
856 // for text such as SIGINT, SIGCONT, SIGSTOP, etc. If no match is found
857 // then we assume the value given is a number and use that.
858 int Translate_Signal(char *my_signal)
859 {
860     int signal_value;
861     int index = 0, found = FALSE;
862     // first check to see if we were passed a string
863     while ( (index < MAX_SIGNAL) && (! found) )
864     {
865         if (! strcmp(my_signal, SIGNAL_NAME[index]) )
866         {
867             found = TRUE;
868             signal_value = SIGNAL_VALUE[index];
869         }
870         else
871            index++;
872     }
873
874     // no value found, try a number
875     if (! found)
876        signal_value = atoi(my_signal);
877
878     return signal_value;
879 }
880
881
882
883 int main(int argc, char **argv) {
884
885         //get program name
886         // char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
887         // program_name = p==NULL?argv[0]:(p+1);
888         program_name = argv[0];
889         int run_in_background = FALSE;
890         //parse arguments
891         int next_option;
892         /* A string listing valid short options letters. */
893         #ifdef LINUX
894         const char* short_options="p:e:P:l:c:s:bfqkmrvzh";
895         PROGRAM_DATA program_data;
896         #else
897         const char* short_options="p:e:P:l:c:s:bfqkrvzh";
898         #endif
899         /* An array describing valid long options. */
900         const struct option long_options[] = {
901                 { "pid", required_argument, NULL, 'p' },
902                 { "exe", required_argument, NULL, 'e' },
903                 { "path", required_argument, NULL, 'P' },
904                 { "limit", required_argument, NULL, 'l' },
905                 { "background", no_argument, NULL, 'b' },
906                 { "foreground", no_argument, NULL, 'f' },
907                 { "quiet", no_argument, NULL, 'q' },
908                 { "verbose", no_argument, NULL, 'v' },
909                 { "lazy", no_argument, NULL, 'z' },
910                 { "help", no_argument, NULL, 'h' },
911                 { "cpu", required_argument, NULL, 'c'},
912                 { "signal", required_argument, NULL, 's'},
913                 #ifdef LINUX
914                 { "monitor-forks", no_argument, NULL, 'm'},
915                 #endif
916                 { NULL, 0, NULL, 0 }
917         };
918         //argument variables
919         const char *exe=NULL;
920         const char *path=NULL;
921         int perclimit=0;
922         int pid_ok = FALSE;
923         int process_ok = FALSE;
924         int limit_ok = FALSE;
925         int last_known_argument = 0;
926         int kill_process = FALSE;   // kill process instead of stopping it
927         int restore_process = FALSE;  // restore killed process
928         int run_child_in_background = TRUE;  // run cpulimit in background when 
929                                              //  we launch new process
930         // struct rlimit maxlimit;
931
932         NCPU = get_ncpu();
933
934         opterr = 0;      // avoid unwanted error messages for unknown parameters
935         do {
936                 next_option = getopt_long (argc, argv, short_options,long_options, NULL);
937                 switch(next_option) {
938                         case 'b':
939                                 run_in_background = TRUE;
940                                 last_known_argument++;
941                                 break;
942                         case 'f':
943                                 run_child_in_background = FALSE;
944                                 run_in_background = FALSE;
945                                 last_known_argument++;
946                                 break;
947                         case 'p':
948                                 pid=atoi(optarg);
949                                 if (pid)   // valid PID
950                                 {
951                                   pid_ok = TRUE;
952                                   lazy = TRUE;
953                                 }
954                                 last_known_argument += 2;
955                                 break;
956                         case 'e':
957                                 exe=optarg;
958                                 process_ok = TRUE;
959                                 last_known_argument += 2;
960                                 break;
961                         case 'P':
962                                 path=optarg;
963                                 process_ok = TRUE;
964                                 last_known_argument += 2;
965                                 break;
966                         case 'l':
967                                 perclimit=atoi(optarg);
968                                 limit_ok = TRUE;
969                                 last_known_argument += 2;
970                                 break;
971                         case 'c':
972                                 NCPU = atoi(optarg);
973                                 last_known_argument += 2;
974                                 break;
975                         case 's':
976                                 send_signal = Translate_Signal(optarg);
977                                 if ( (send_signal < 1) || (send_signal > 35) )
978                                 {
979                                     fprintf(stderr, "Specified exit signal is not recognized or not within bounds (1-35). Using SIGCONT.\n");
980                                     send_signal = SIGCONT;
981                                 }
982                                 last_known_argument += 2;
983                         case 'k':
984                                 kill_process = TRUE;
985                                 last_known_argument++;
986                                 break;
987                         #ifdef LINUX
988                         case 'm':
989                                 monitor_children = TRUE;
990                                 last_known_argument++;
991                                 break;
992                         #endif
993                         case 'r':
994                                 restore_process = TRUE;
995                                 last_known_argument++;
996                                 break;
997
998                         case 'v':
999                                 verbose = TRUE;
1000                                 last_known_argument++;
1001                                 break;
1002                         case 'q':
1003                                 quiet = TRUE;
1004                                 last_known_argument++;
1005                                 break;
1006                         case 'z':
1007                                 lazy = TRUE;
1008                                 last_known_argument++;
1009                                 break;
1010                         case 'h':
1011                                 print_usage (stdout, 1);
1012                                 last_known_argument++;
1013                                 break;
1014                         case 'o':
1015                                 last_known_argument++;
1016                                 next_option = -1;
1017                                 break;
1018                         case '?':
1019                                 print_usage (stderr, 1);
1020                                 last_known_argument++;
1021                                 break;
1022                         case -1:
1023                                 break;
1024                         // default:
1025                         //      abort();
1026                 }
1027         } while(next_option != -1);
1028
1029         signal(SIGCHLD, Child_Done);
1030
1031         // try to launch a program passed on the command line
1032         // But only if we do not already have a PID to watch
1033         if ( (last_known_argument + 1 < argc) && (pid_ok == FALSE) )
1034         {
1035            last_known_argument++;
1036            // if we stopped on "--" jump to the next parameter
1037            if ( (last_known_argument + 1 < argc) && (! strcmp(argv[last_known_argument], "--") ) )
1038                last_known_argument++;
1039            pid_t forked_pid;
1040            // try to launch remaining arguments
1041            if (verbose)
1042            {
1043                int index = last_known_argument;
1044                printf("Launching %s", argv[index]);
1045                for (index = last_known_argument + 1; index < argc; index++)
1046                     printf(" %s", argv[index]);
1047                printf(" with limit %d\n", perclimit);
1048            }
1049            forked_pid = fork();
1050            if (forked_pid == -1)  // error
1051            {
1052                printf("Failed to launch specified process.\n");
1053                exit(1);
1054            }
1055            else if (forked_pid == 0)   // target child
1056            {
1057               execvp(argv[last_known_argument],
1058                      &(argv[last_known_argument]) );
1059               exit(2);
1060            }
1061            else     // parent who will now fork the throttler
1062            {
1063               pid_t limit_pid;
1064               // if we are planning to kill a process, give it
1065               // a running head start to avoid death at start-up
1066               if (kill_process)
1067                  sleep(5);
1068     
1069               /* The following block assumes we want to run cpulimit in the
1070                  background. This is the default behaviour.
1071               */ 
1072               if (run_child_in_background)
1073               {
1074                  limit_pid = fork();
1075                  if (limit_pid == 0)   // child cpulimit process running in background
1076                  {
1077                     pid = forked_pid;    // the first child, target process
1078                     lazy = TRUE;
1079                     pid_ok = TRUE;
1080                     if (verbose)
1081                       printf("Throttling process %d\n", (int) pid);
1082                  }
1083                  else    // parent cpulimit process which can quit
1084                    exit(0);
1085               }  // end of running in background
1086               else
1087               {
1088                   pid = forked_pid;
1089                   lazy = TRUE;
1090                   pid_ok = TRUE;
1091                   run_in_background = FALSE;
1092               }  // end of running in foreground
1093
1094            }  // end of parent that launched target
1095
1096         }      // end of launching child process
1097
1098         if (!process_ok && !pid_ok) {
1099                 fprintf(stderr,"Error: You must specify a target process\n");
1100                 print_usage (stderr, 1);
1101                 exit(1);
1102         }
1103         if ((exe!=NULL && path!=NULL) || (pid_ok && (exe!=NULL || path!=NULL))) {
1104                 fprintf(stderr,"Error: You must specify exactly one target process\n");
1105                 print_usage (stderr, 1);
1106                 exit(1);
1107         }
1108         if (!limit_ok) {
1109                 fprintf(stderr,"Error: You must specify a cpu limit\n");
1110                 print_usage (stderr, 1);
1111                 exit(1);
1112         }
1113         float limit=perclimit/100.0;
1114         if ( (limit <= 0.00) || (limit > NCPU) )
1115         {
1116                 fprintf(stderr,"Error: limit must be in the range of 1 to %d00\n", NCPU);
1117                 print_usage (stderr, 1);
1118                 exit(1);
1119         }
1120
1121         // check to see if we should fork
1122         if (run_in_background)
1123         {
1124              pid_t process_id;
1125              process_id = fork();
1126              if (! process_id)
1127                 exit(0);
1128              else
1129              {
1130                 setsid();
1131                 process_id = fork();
1132                 if (process_id)
1133                   exit(0);
1134              }
1135         }
1136
1137         //parameters are all ok!
1138         signal(SIGINT,quit);
1139         signal(SIGTERM,quit);
1140
1141         my_pid = getpid();
1142         if (verbose)
1143            printf("%d CPUs detected.\n", NCPU);
1144
1145         increase_priority();
1146
1147         //time quantum in microseconds. it's splitted in a working period and a sleeping one
1148         int period=100000;
1149         struct timespec twork,tsleep;   //working and sleeping intervals
1150         memset(&twork,0,sizeof(struct timespec));
1151         memset(&tsleep,0,sizeof(struct timespec));
1152
1153 wait_for_process:
1154
1155         //look for the target process..or wait for it
1156         if (exe != NULL)
1157                 pid=getpidof(exe);
1158         else if (path != NULL)
1159                 pid=getpidof(path);
1160         else 
1161                 waitforpid(pid);
1162
1163         
1164         //process detected...let's play
1165
1166         //init compute_cpu_usage internal stuff
1167         compute_cpu_usage(0,0,NULL);
1168         //main loop counter
1169         int i=0;
1170
1171         struct timespec startwork,endwork;
1172         long workingtime=0;             //last working time in microseconds
1173
1174         if (verbose) print_caption();
1175
1176         float pcpu_avg=0;
1177
1178         // On Linux we can monitor child processes of the target
1179         #ifdef LINUX
1180         if (monitor_children)
1181         {
1182            pthread_t my_thread;
1183            int thread_status;
1184            if (verbose)
1185               printf("Starting fork monitoring thread...\n");
1186            program_data.this_program = argv[0];
1187            program_data.limit = perclimit;
1188            thread_status = pthread_create(&my_thread, NULL, 
1189                                           Monitor_Children, &program_data);
1190            if ( (thread_status) && (verbose) )
1191               printf("Creating fork monitoring thread failed.\n");
1192         }
1193         #endif
1194
1195         //here we should already have high priority, for time precision
1196         while(1) {
1197
1198                 //estimate how much the controlled process is using the cpu in its working interval
1199                 struct cpu_usage cu;
1200                 if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
1201                      if (!quiet)
1202                         fprintf(stderr,"Process %d dead!\n",pid);
1203                      if (lazy) 
1204                         exit(2);
1205                      //wait until our process appears
1206                      goto wait_for_process;             
1207                 }
1208
1209                 //cpu actual usage of process (range 0-1)
1210                 float pcpu=cu.pcpu;
1211                 //rate at which we are keeping active the process (range 0-1)
1212                 float workingrate=cu.workingrate;
1213
1214                 //adjust work and sleep time slices
1215                 if (pcpu>0) {
1216                         twork.tv_nsec=min(period*limit*1000/pcpu*workingrate,period*1000);
1217                 }
1218                 else if (pcpu==0) {
1219                         twork.tv_nsec=period*1000;
1220                 }
1221                 else if (pcpu==-1) {
1222                         //not yet a valid idea of cpu usage
1223                         pcpu=limit;
1224                         workingrate=limit;
1225                         twork.tv_nsec=min(period*limit*1000,period*1000);
1226                 }
1227                 tsleep.tv_nsec=period*1000-twork.tv_nsec;
1228
1229                 //update average usage
1230                 pcpu_avg=(pcpu_avg*i+pcpu)/(i+1);
1231
1232                 if (verbose && i%10==0 && i>0) {
1233                         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);
1234                         if (i%200 == 0)
1235                            print_caption();
1236                 }
1237
1238                 // if (limit<1 && limit>0) {
1239                 // printf("Comparing %f to %f\n", pcpu, limit);
1240                 if (pcpu < limit)
1241                 {
1242                         // printf("Continue\n");
1243                         //resume process
1244                         if (kill(pid,SIGCONT)!=0) {
1245                              if (!quiet)
1246                                 fprintf(stderr,"Process %d dead!\n",pid);
1247                              if (lazy) exit(2);
1248                                 //wait until our process appears
1249                                 goto wait_for_process;
1250                         }
1251                 }
1252
1253                 #ifdef __APPLE_
1254                 // OS X does not have clock_gettime, use clock_get_time
1255                 clock_serv_t cclock;
1256                 mach_timespec_t mts;
1257                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
1258                 clock_get_time(cclock, &mts);
1259                 mach_port_deallocate(mach_task_self(), cclock);
1260                 startwork.tv_sec = mts.tv_sec;
1261                 startwork.tv_nsec = mts.tv_nsec;
1262
1263                 #else
1264                 clock_gettime(CLOCK_REALTIME,&startwork);
1265                 #endif
1266
1267                 nanosleep(&twork,NULL);         //now process is working
1268                 #ifdef __APPLE__
1269                 // OS X does not have clock_gettime, use clock_get_time
1270                 // clock_serv_t cclock;
1271                 // mach_timespec_t mts;
1272                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
1273                 clock_get_time(cclock, &mts);
1274                 mach_port_deallocate(mach_task_self(), cclock);
1275                 endwork.tv_sec = mts.tv_sec;
1276                 endwork.tv_nsec = mts.tv_nsec;
1277
1278                 #else
1279                 clock_gettime(CLOCK_REALTIME,&endwork);
1280                 #endif
1281                 workingtime=timediff(&endwork,&startwork);
1282
1283                 // if (limit<1) {
1284                 // printf("Checking %f vs %f\n", pcpu, limit);
1285                 if (pcpu > limit)
1286                 {
1287                      // When over our limit we may run into
1288                      // situations where we want to kill
1289                      // the offending process, then restart it
1290                      if (kill_process)
1291                      {
1292                          kill(pid, SIGKILL);
1293                          if (!quiet)
1294                              fprintf(stderr, "Process %d killed.\n", pid);
1295                          if ( (lazy) && (! restore_process) ) 
1296                               exit(2);
1297                          // restart killed process
1298                          if (restore_process)
1299                          {
1300                              pid_t new_process;
1301                              new_process = fork();
1302                              if (new_process == -1)
1303                              {
1304                               fprintf(stderr, "Failed to restore killed process.\n");
1305                              }
1306                              else if (new_process == 0)
1307                              {
1308                                 // child which becomes new process
1309                                 if (verbose)
1310                                    printf("Relaunching %s\n",
1311                                           argv[last_known_argument]);
1312                                 execvp(argv[last_known_argument],
1313                                        &(argv[last_known_argument]) ); 
1314                              }
1315                              else // parent
1316                              {
1317                                 // we need to track new process
1318                                 pid = new_process;
1319                                 // avoid killing child process
1320                                 sleep(5);
1321                              }
1322                          }
1323                      }
1324                      // do not kill process, just throttle it
1325                      else
1326                      {
1327
1328                         // printf("Stop\n");
1329                         //stop process, it has worked enough
1330                         if (kill(pid,SIGSTOP)!=0) {
1331                             if (!quiet)
1332                                 fprintf(stderr,"Process %d dead!\n", pid);
1333                             if (lazy) exit(2);
1334                                 //wait until our process appears
1335                                 goto wait_for_process;
1336                         }
1337                         nanosleep(&tsleep,NULL);        //now process is sleeping
1338                       }   // end of throttle process
1339                 }         // end of process using too much CPU
1340                 i++;
1341         }
1342
1343    return 0;
1344 }