Imported Upstream version 2.2 upstream/2.2
authorgregor herrmann <gregoa@debian.org>
Sun, 25 May 2014 18:10:07 +0000 (20:10 +0200)
committergregor herrmann <gregoa@debian.org>
Sun, 25 May 2014 18:10:07 +0000 (20:10 +0200)
CHANGELOG
Makefile
README
TODO
cpulimit.1 [new file with mode: 0644]
cpulimit.1.gz [deleted file]
cpulimit.c

index bf11a1a..0a921ad 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,27 @@
+=========== Changes in 2.2 ================
+
+* Escaped double-dashed in manual page to avoid
+  warnings from Debian check tool.
+
+* Added -s --signal flag. This flag allows the user to
+  specify an alternative signal to send a watched process
+  when cpulimit terminates. By default we send SIGCONT.
+  The -s flag can accept a number (1-35) or a written
+  value such as SIGCONT, SIGSTOP, SIGINT, SIGTERM.
+
+
+=========== Changes in 2.1 ================
+
+* Added the --quiet (-q) flag to make 
+  limitcpu run silently
+
+* Make sure error messages are printed to stderr.
+
+* Placed source code in Subversion (svn) repository.
+  Accessable using the SVN checkout command. For
+  details, please see the README file.
+
+
 =========== Changes in 2.0 ================
 
 * Added the -- flag to make sure child processes
 =========== Changes in 2.0 ================
 
 * Added the -- flag to make sure child processes
index b498c1b..6ca6b08 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION?=2.0
+VERSION?=2.2
 PREFIX?=/usr
 CFLAGS?=-Wall -O2 -DVERSION=$(VERSION)
 CC?=gcc
 PREFIX?=/usr
 CFLAGS?=-Wall -O2 -DVERSION=$(VERSION)
 CC?=gcc
@@ -24,16 +24,16 @@ install: cpulimit
        mkdir -p ${PREFIX}/bin
        mkdir -p ${PREFIX}/share/man/man1
        cp cpulimit ${PREFIX}/bin
        mkdir -p ${PREFIX}/bin
        mkdir -p ${PREFIX}/share/man/man1
        cp cpulimit ${PREFIX}/bin
-       cp cpulimit.1.gz ${PREFIX}/share/man/man1
+       cp cpulimit.1 ${PREFIX}/share/man/man1
 
 deinstall:
        rm -f ${PREFIX}/bin/cpulimit
 
 deinstall:
        rm -f ${PREFIX}/bin/cpulimit
-       rm -f ${PREFIX}/share/man/man1/cpulimit.1.gz
+       rm -f ${PREFIX}/share/man/man1/cpulimit.1
 
 clean:
        rm -f *~ cpulimit
        $(MAKE) -C test clean
 
 tarball: clean
 
 clean:
        rm -f *~ cpulimit
        $(MAKE) -C test clean
 
 tarball: clean
-       cd .. && tar czf cpulimit-$(VERSION).tar.gz cpulimit-$(VERSION)
+       cd .. && tar czf cpulimit-$(VERSION).tar.gz cpulimit-$(VERSION) --exclude=.svn
        
        
diff --git a/README b/README
index 7aa2470..83b6902 100644 (file)
--- a/README
+++ b/README
@@ -42,11 +42,11 @@ How to compile and install
 Once you have downloaded a copy of LimitCPU building should be fairly
 straight forward. First we unpack the source code
 
 Once you have downloaded a copy of LimitCPU building should be fairly
 straight forward. First we unpack the source code
 
-tar zxf cpulimit-2.0.tar.gz
+tar zxf cpulimit-2.2.tar.gz
 
 Then we run the makefile.
 
 
 Then we run the makefile.
 
-cd cpulimit-2.0
+cd cpulimit-2.2
 make
 
 This should produce the executable file "cpulimit". If you would like
 make
 
 This should produce the executable file "cpulimit". If you would like
@@ -166,7 +166,32 @@ has been launched by cpulimit. For this reason it is necessary
 to specify the target program at the end of the command line
 as shown above.
 
 to specify the target program at the end of the command line
 as shown above.
 
+LimitCPU, by default, will tell a watched process to continue
+running when LimitCPU terminates. This is accomplished by
+sending the watched process the SIGCONT signal just before
+LimitCPU exits. The user can specify an alternative signal to
+send the watched process when LimitCPU terminates. This is
+accomplished using the -s or --signal command line flag. Here
+is an example of terminating a watched process
 
 
+cpulimit -l 25 -p 1234 -s SIGTERM
+
+And here we accomplish the same thing using a numeric value
+instead of the written form of the signal.
+
+cpulimit -l 25 -p 1234 --signal=15
+
+
+
+
+Accessing the latest code
+============================
+
+For developers who would like to test or modify the latest
+LimitCPU code, the code is available in a Subversion (svn)
+repository. The code can be checked out using the command
+
+svn checkout svn://svn.code.sf.net/p/limitcpu/code/ limitcpu-code
 
 
 
 
 
 
diff --git a/TODO b/TODO
index 9915917..960d715 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
 - light and scalable algorithm for subprocesses detection and limitation
 
 - light and scalable algorithm for subprocesses detection and limitation
 
-- Put source in svn
 
 
diff --git a/cpulimit.1 b/cpulimit.1
new file mode 100644 (file)
index 0000000..8e6f0e2
--- /dev/null
@@ -0,0 +1,119 @@
+.TH CPULIMIT "1" "June 2012" "cpulimit" "User commands"
+.SH NAME
+cpulimit -- limits the CPU usage of a process
+.SH SYNOPSIS
+.B cpulimit
+\fI[TARGET\fR] \fR[\fIOPTIONS\fR...] \fR[ -- \fIPROGRAM\fR]
+.SH DESCRIPTION
+.P
+\fITARGET \fRmust be exactly one of these:
+.TP
+\fB\-p\fR, \fB\-\-pid\fR=\fIN\fR
+pid of the process
+.TP
+\fB\-e\fR, \fB\-\-exe\fR=\fIFILE\fR
+name of the executable program file
+.TP
+\fB\-P\fR, \fB\-\-path\fR=\fIPATH\fR
+absolute path name of the executable program file
+.P
+\fIOPTIONS\fR
+.TP
+\fB\-b\fR, \fB\-\-background\fR
+run cpulimit in the background, freeing up the terminal
+.TP
+\fB\-c\fR, \fB\-\-cpu\fR
+specify the number of CPU cores available. Usually this is detected for us.
+.TP
+\fB\-l\fR, \fB\-\-limit\fR=\fIN\fR
+percentage of CPU allowed from 1 up. Usually 1 - 100, but can be higher on multi-core CPUs. (mandatory)
+.TP
+\fB\-q\fR, \fB\-\-quiet\fR
+Runs in quiet mode, avoids writing update messages to console.
+.TP
+\fB\-k\fR, \fB\-\-kill\fR
+kill target process instead of throttling its CPU usage
+.TP
+\fB\-r\fR, \fB\-\-restore\fR
+restore a process killed using the \-k flag.
+.TP
+\fB\-s\fR, \fB\-\-signal\fR
+send an alternative signal to the watched process when we exit. Default is SIGCONT.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+show control statistics
+.TP
+\fB\-z\fR, \fB\-\-lazy\fR
+exit if there is no suitable target process, or if it dies
+.TP
+\fB\--\fR 
+This is the final CPUlimit option. All following 
+options are for another program we will launch.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+display this help and exit
+.SH EXAMPLES
+Assuming you have started \fB`foo \-\-bar`\fR and you find out with \fItop\fR(1) or
+\fIps\fR(1) that this process uses all your CPU time you can either
+.TP
+\[sh] \fBcpulimit \-e foo \-l 50\fR
+limits the CPU usage of the process by acting on the executable program file
+(note: the argument "\-\-bar" is omitted)
+.TP
+\[sh] \fBcpulimit \-p 1234 \-l 50\fR
+limits the CPU usage of the process by acting on its PID, as shown by
+\fIps\fR(1)
+.TP
+\[sh] \fBcpulimit \-P /usr/bin/foo \-l 50\fR
+same as \fI\-e\fR but uses the absolute path name
+.TP
+\[sh] \fB/usr/bin/someapp \&
+.TP
+\[sh] \fBcpulimit \-p $! \-l 25 \-b\fR
+Useful for scripts where you want to throttle
+the last command run.
+.TP
+\[sh] \fBcpulimit \-l 20 firefox\fR
+Launch Firefox web browser and limit its CPU usage to
+20%
+.TP
+\[sh] \fBcpulimit \-l 25 \-\- firefox \-private\fR
+Launch Firefox web browser in private mode and limit its CPU usage to
+25%
+.TP
+\[sh] \fBcpulimit \-c 2 \-p 12345 \-l 25\fR
+The \fB\-c\fR flag sets the number of CPU cores the
+program thinks are available. Usually this is detected
+for us, but can be over-ridden.
+.TP
+\[sh] \fBcpulimit \-l 20 \-k firefox\fr
+Launch the Firefox program and kill it if the process goes
+over 20% CPU usage.
+.TP
+\[sh] \fBcpulimit \-l 20 \-p 1234 -s SIGTERM
+Throttle process 1234 at 20% CPU usage. If cpulimit is forced to exit, 
+it sends the watched process the SIGTERM signal.
+.SH NOTES
+.IP \(bu 4
+cpulimit always sends the SIGSTOP and SIGCONT signals to a process, 
+both to verify
+that it can control it and 
+to limit the average amount of CPU it consumes.  This can result in
+misleading (annoying) job control messages that indicate that the job 
+has been stopped (when actually it was, but immediately restarted).  
+This can also cause issues with interactive shells that detect or otherwise
+depend on SIGSTOP/SIGCONT.   For example,
+you may place a job in the foreground, only to see it immediately stopped
+and restarted in the background.  (See also <http://bugs.debian.org/558763>.)
+.IP \(bu 4
+When invoked with the \fI\-e\fR or \fI\-P\fR options, cpulimit looks for 
+any process under /proc with a name that matches the process name argument 
+given.  Furthermore, it uses the first instance of the process found.  
+To control a specific instance of a process, use the \fI\-p\fR option 
+and provide a PID.
+.IP \(bu 4
+The current version of cpulimit assumes the kernel HZ value 100.
+
+.SH AUTHOR
+This manpage was written for the Debian project by gregor herrmann 
+<gregoa@debian.org> but may be used by others.
diff --git a/cpulimit.1.gz b/cpulimit.1.gz
deleted file mode 100644 (file)
index 493e513..0000000
Binary files a/cpulimit.1.gz and /dev/null differ
index 271cd3f..ef24e97 100644 (file)
@@ -18,6 +18,9 @@
  * Date: Jan 29, 2013
  * Version 1.2 and newer
  *
  * Date: Jan 29, 2013
  * Version 1.2 and newer
  *
+ * Modifications and updates by: Hasnain Lakhani
+ * Date: Mar 26, 2014
+ * Version 2.1
  */
 
 
  */
 
 
@@ -77,7 +80,7 @@
 #endif
 
 #ifndef VERSION
 #endif
 
 #ifndef VERSION
-#define VERSION 2.0
+#define VERSION 2.1
 #endif
 
 //pid of the controlled process
 #endif
 
 //pid of the controlled process
@@ -96,9 +99,21 @@ int nice_lim;
 // number of CPUs we detected
 int NCPU;
 
 // number of CPUs we detected
 int NCPU;
 
+// quiet mode
+int quiet = FALSE;
+
+// What signal should we send to the watched process
+// when cpulimit exits?
+int send_signal = SIGCONT;
+
 //reverse byte search
 // void *memrchr(const void *s, int c, size_t n);
 
 //reverse byte search
 // void *memrchr(const void *s, int c, size_t n);
 
+#define MAX_SIGNAL 7
+const char *SIGNAL_NAME[MAX_SIGNAL] = { "SIGHUP", "SIGINT", "SIGQUIT", 
+                                 "SIGKILL", "SIGTERM", "SIGSTOP", "SIGCONT" };
+const int SIGNAL_VALUE[MAX_SIGNAL] = { SIGHUP, SIGINT, SIGQUIT,
+                                  SIGKILL, SIGTERM, SIGSTOP, SIGCONT };
 
 
 //return ta-tb in microseconds (no overflow checks!)
 
 
 //return ta-tb in microseconds (no overflow checks!)
@@ -116,7 +131,7 @@ int Check_Us(pid_t target_pid)
    this_pid = getpid();
    if (this_pid == target_pid)
    {
    this_pid = getpid();
    if (this_pid == target_pid)
    {
-      printf("We cannot throttle ourselves.\n");
+      fprintf(stderr, "We cannot throttle ourselves.\n");
       exit(7);
    }
    return TRUE;
       exit(7);
    }
    return TRUE;
@@ -178,7 +193,7 @@ int waitforpid(int pid) {
                                exit(2);
                        }
                        else {
                                exit(2);
                        }
                        else {
-                               printf("Warning: no target process found. Waiting for it...\n");
+                               fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
                        }
                }
 
                        }
                }
 
@@ -187,7 +202,8 @@ int waitforpid(int pid) {
        }
 
 done:
        }
 
 done:
-       printf("Process %d detected\n",pid);
+    if (!quiet)
+       printf("Process %d detected\n",pid);
        //now set high priority, if possible
        // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
         /*
        //now set high priority, if possible
        // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
         /*
@@ -282,7 +298,7 @@ int getpidof(const char *process) {
                                exit(2);
                        }
                        else {
                                exit(2);
                        }
                        else {
-                               printf("Warning: no target process found. Waiting for it...\n");
+                               fprintf(stderr, "Warning: no target process found. Waiting for it...\n");
                        }
                }
 
                        }
                }
 
@@ -291,7 +307,8 @@ int getpidof(const char *process) {
        }
 
 done:
        }
 
 done:
-       printf("Process %d detected\n",pid);
+    if (!quiet)
+       printf("Process %d detected\n",pid);
        //now set high priority, if possible
        // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
         /*
        //now set high priority, if possible
        // if (setpriority(PRIO_PROCESS,getpid(),-20)!=0) {
         /*
@@ -306,8 +323,8 @@ done:
 
 //SIGINT and SIGTERM signal handler
 void quit(int sig) {
 
 //SIGINT and SIGTERM signal handler
 void quit(int sig) {
-       //let the process continue if it's stopped
-       kill(pid,SIGCONT);
+       //let the process continue if we are stopped
+       kill(pid, send_signal);
        printf("Exiting...\n");
        exit(0);
 }
        printf("Exiting...\n");
        exit(0);
 }
@@ -325,7 +342,7 @@ int getjiffies(int pid)
    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
    if (! my_kernel)
    {
    my_kernel = kvm_open(0, 0, 0, O_RDONLY, "kvm_open");
    if (! my_kernel)
    {
-      printf("Error opening kernel vm. You should be running as root.\n");
+      fprintf(stderr, "Error opening kernel vm. You should be running as root.\n");
       return -1;
    }
 
       return -1;
    }
 
@@ -499,11 +516,14 @@ void print_usage(FILE *stream,int exit_code) {
        fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
        fprintf(stream, "      -l, --limit=N      percentage of cpu allowed from 1 up.\n");
         fprintf(stream, "                         Usually 1 - %d00, but can be higher\n", NCPU);
         fprintf(stream, "                         on multi-core CPUs (mandatory)\n");
+        fprintf(stream, "      -q, --quiet        run in quiet mode (only print errors).\n");
         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
         fprintf(stream, "                         instead of just throttling them.\n");
         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
         fprintf(stream, "                         been killed. Works with the -k flag.\n");
         fprintf(stream, "      -k, --kill         kill processes going over their limit\n");
         fprintf(stream, "                         instead of just throttling them.\n");
         fprintf(stream, "      -r, --restore      Restore processes after they have\n");
         fprintf(stream, "                         been killed. Works with the -k flag.\n");
-
+        fprintf(stream, "      -s, --signal=SIG   Send this signal to the watched process when cpulimit exits.\n");
+        fprintf(stream, "                         Signal should be specificed as a number or \n");
+        fprintf(stream, "                         SIGTERM, SIGCONT, SIGSTOP, etc. SIGCONT is the default.\n");
        fprintf(stream, "      -v, --verbose      show control statistics\n");
        fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
         fprintf(stream, "                         or if it dies\n");
        fprintf(stream, "      -v, --verbose      show control statistics\n");
        fprintf(stream, "      -z, --lazy         exit if there is no suitable target process,\n");
         fprintf(stream, "                         or if it dies\n");
@@ -526,6 +546,33 @@ int get_ncpu()
 }
 
 
 }
 
 
+// This function attempts to figure out what signal we should send
+// target processes based on a command line paramter. First we check
+// for text such as SIGINT, SIGCONT, SIGSTOP, etc. If no match is found
+// then we assume the value given is a number and use that.
+int Translate_Signal(char *my_signal)
+{
+    int signal_value;
+    int index = 0, found = FALSE;
+    // first check to see if we were passed a string
+    while ( (index < MAX_SIGNAL) && (! found) )
+    {
+        if (! strcmp(my_signal, SIGNAL_NAME[index]) )
+        {
+            found = TRUE;
+            signal_value = SIGNAL_VALUE[index];
+        }
+        else
+           index++;
+    }
+
+    // no value found, try a number
+    if (! found)
+       signal_value = atoi(my_signal);
+
+    return signal_value;
+}
+
 
 
 int main(int argc, char **argv) {
 
 
 int main(int argc, char **argv) {
@@ -538,7 +585,7 @@ int main(int argc, char **argv) {
        //parse arguments
        int next_option;
        /* A string listing valid short options letters. */
        //parse arguments
        int next_option;
        /* A string listing valid short options letters. */
-       const char* short_options="p:e:P:l:c:bkrvzh";
+       const char* short_options="p:e:P:l:c:s:bqkrvzh";
        /* An array describing valid long options. */
        const struct option long_options[] = {
                { "pid", required_argument, NULL, 'p' },
        /* An array describing valid long options. */
        const struct option long_options[] = {
                { "pid", required_argument, NULL, 'p' },
@@ -546,10 +593,12 @@ int main(int argc, char **argv) {
                { "path", required_argument, NULL, 'P' },
                { "limit", required_argument, NULL, 'l' },
                 { "background", no_argument, NULL, 'b' },
                { "path", required_argument, NULL, 'P' },
                { "limit", required_argument, NULL, 'l' },
                 { "background", no_argument, NULL, 'b' },
+                { "quiet", no_argument, NULL, 'q' },
                { "verbose", no_argument, NULL, 'v' },
                { "lazy", no_argument, NULL, 'z' },
                { "help", no_argument, NULL, 'h' },
                 { "cpu", required_argument, NULL, 'c'},
                { "verbose", no_argument, NULL, 'v' },
                { "lazy", no_argument, NULL, 'z' },
                { "help", no_argument, NULL, 'h' },
                 { "cpu", required_argument, NULL, 'c'},
+                { "signal", required_argument, NULL, 's'},
                { NULL, 0, NULL, 0 }
        };
        //argument variables
                { NULL, 0, NULL, 0 }
        };
        //argument variables
@@ -602,6 +651,14 @@ int main(int argc, char **argv) {
                                 NCPU = atoi(optarg);
                                 last_known_argument += 2;
                                 break;
                                 NCPU = atoi(optarg);
                                 last_known_argument += 2;
                                 break;
+                        case 's':
+                                send_signal = Translate_Signal(optarg);
+                                if ( (send_signal < 1) || (send_signal > 35) )
+                                {
+                                    fprintf(stderr, "Specified exit signal is not recognized or not within bounds (1-35). Using SIGCONT.\n");
+                                    send_signal = SIGCONT;
+                                }
+                                last_known_argument += 2;
                         case 'k':
                                 kill_process = TRUE;
                                 last_known_argument++;
                         case 'k':
                                 kill_process = TRUE;
                                 last_known_argument++;
@@ -615,6 +672,10 @@ int main(int argc, char **argv) {
                                verbose = TRUE;
                                 last_known_argument++;
                                break;
                                verbose = TRUE;
                                 last_known_argument++;
                                break;
+                        case 'q':
+                                quiet = TRUE;
+                                last_known_argument++;
+                                break;
                        case 'z':
                                lazy = TRUE;
                                 last_known_argument++;
                        case 'z':
                                lazy = TRUE;
                                 last_known_argument++;
@@ -841,7 +902,8 @@ wait_for_process:
                //estimate how much the controlled process is using the cpu in its working interval
                struct cpu_usage cu;
                if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
                //estimate how much the controlled process is using the cpu in its working interval
                struct cpu_usage cu;
                if (compute_cpu_usage(pid,workingtime,&cu)==-1) {
-                       fprintf(stderr,"Process %d dead!\n",pid);
+            if (!quiet)
+                       fprintf(stderr,"Process %d dead!\n",pid);
                        if (lazy) exit(2);
                        //wait until our process appears
                        goto wait_for_process;          
                        if (lazy) exit(2);
                        //wait until our process appears
                        goto wait_for_process;          
@@ -883,7 +945,8 @@ wait_for_process:
                         // printf("Continue\n");
                        //resume process
                        if (kill(pid,SIGCONT)!=0) {
                         // printf("Continue\n");
                        //resume process
                        if (kill(pid,SIGCONT)!=0) {
-                               fprintf(stderr,"Process %d dead!\n",pid);
+                if (!quiet)
+                               fprintf(stderr,"Process %d dead!\n",pid);
                                if (lazy) exit(2);
                                //wait until our process appears
                                goto wait_for_process;
                                if (lazy) exit(2);
                                //wait until our process appears
                                goto wait_for_process;
@@ -930,7 +993,8 @@ wait_for_process:
                      if (kill_process)
                      {
                          kill(pid, SIGKILL);
                      if (kill_process)
                      {
                          kill(pid, SIGKILL);
-                         fprintf(stderr, "Process %d killed.\n", pid);
+                         if (!quiet)
+                             fprintf(stderr, "Process %d killed.\n", pid);
                          if ( (lazy) && (! restore_process) ) 
                               exit(2);
                          // restart killed process
                          if ( (lazy) && (! restore_process) ) 
                               exit(2);
                          // restart killed process
@@ -967,7 +1031,8 @@ wait_for_process:
                         // printf("Stop\n");
                        //stop process, it has worked enough
                        if (kill(pid,SIGSTOP)!=0) {
                         // printf("Stop\n");
                        //stop process, it has worked enough
                        if (kill(pid,SIGSTOP)!=0) {
-                               fprintf(stderr,"Process %d dead!\n", pid);
+                if (!quiet)
+                               fprintf(stderr,"Process %d dead!\n", pid);
                                if (lazy) exit(2);
                                //wait until our process appears
                                goto wait_for_process;
                                if (lazy) exit(2);
                                //wait until our process appears
                                goto wait_for_process;