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
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
@@ -24,16 +24,16 @@ install: cpulimit
        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
-       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
-       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
 
-tar zxf cpulimit-2.0.tar.gz
+tar zxf cpulimit-2.2.tar.gz
 
 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
@@ -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.
 
+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
 
-- 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
  *
+ * Modifications and updates by: Hasnain Lakhani
+ * Date: Mar 26, 2014
+ * Version 2.1
  */
 
 
@@ -77,7 +80,7 @@
 #endif
 
 #ifndef VERSION
-#define VERSION 2.0
+#define VERSION 2.1
 #endif
 
 //pid of the controlled process
@@ -96,9 +99,21 @@ int nice_lim;
 // 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);
 
+#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!)
@@ -116,7 +131,7 @@ int Check_Us(pid_t 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;
@@ -178,7 +193,7 @@ int waitforpid(int pid) {
                                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:
-       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) {
         /*
@@ -282,7 +298,7 @@ int getpidof(const char *process) {
                                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:
-       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) {
         /*
@@ -306,8 +323,8 @@ done:
 
 //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);
 }
@@ -325,7 +342,7 @@ int getjiffies(int pid)
    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;
    }
 
@@ -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, "      -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, "      -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");
@@ -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) {
@@ -538,7 +585,7 @@ int main(int argc, char **argv) {
        //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' },
@@ -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' },
+                { "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'},
+                { "signal", required_argument, NULL, 's'},
                { NULL, 0, NULL, 0 }
        };
        //argument variables
@@ -602,6 +651,14 @@ int main(int argc, char **argv) {
                                 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++;
@@ -615,6 +672,10 @@ int main(int argc, char **argv) {
                                verbose = TRUE;
                                 last_known_argument++;
                                break;
+                        case 'q':
+                                quiet = TRUE;
+                                last_known_argument++;
+                                break;
                        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) {
-                       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;          
@@ -883,7 +945,8 @@ wait_for_process:
                         // 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;
@@ -930,7 +993,8 @@ wait_for_process:
                      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
@@ -967,7 +1031,8 @@ wait_for_process:
                         // 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;