aboutsummaryrefslogtreecommitdiffstats
path: root/src/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/process.c')
-rw-r--r--src/process.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/process.c b/src/process.c
new file mode 100644
index 0000000..398d9e9
--- /dev/null
+++ b/src/process.c
@@ -0,0 +1,233 @@
+/**
+ *
+ * cpulimit - a cpu limiter for Linux
+ *
+ * Copyright (C) 2005-2008, by: Angelo Marletta <marlonx80@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+//TODO: add documentation to public functions
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/utsname.h>
+
+#include "process.h"
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#include <errno.h>
+#endif
+
+#ifdef __linux__
+int get_proc_info(struct process *p, pid_t pid) {
+/* static char statfile[20];
+ static char buffer[64];
+ int ret;
+ sprintf(statfile, "/proc/%d/stat", pid);
+ FILE *fd = fopen(statfile, "r");
+ if (fd==NULL) return -1;
+ fgets(buffer, sizeof(buffer), fd);
+ fclose(fd);
+
+ char state;
+
+ int n = sscanf(buffer, "%d %s %c %d %d %d %d %d "
+ "%lu %lu %lu %lu %lu %lu %lu "
+ "%ld %ld %ld %ld %ld %ld "
+ "%lu ",
+ &p->pid,
+ &p->command,
+ &state,
+ NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+ &utime,&stime,&cutime,&cstime,
+ NULL,NULL,NULL,NULL,
+ &starttime,
+ );*/
+ return 0;
+}
+#elif defined __APPLE__
+int get_proc_info(struct process *p, pid_t pid) {
+ int err;
+ struct kinfo_proc *result = NULL;
+ size_t length;
+ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
+
+ /* We start by calling sysctl with result == NULL and length == 0.
+ That will succeed, and set length to the appropriate length.
+ We then allocate a buffer of that size and call sysctl again
+ with that buffer.
+ */
+ length = 0;
+ err = sysctl(mib, 4, NULL, &length, NULL, 0);
+ if (err == -1) {
+ err = errno;
+ }
+ if (err == 0) {
+ result = malloc(length);
+ err = sysctl(mib, 4, result, &length, NULL, 0);
+ if (err == -1)
+ err = errno;
+ if (err == ENOMEM) {
+ free(result); /* clean up */
+ result = NULL;
+ }
+ }
+
+ p->pid = result->kp_proc.p_pid;
+ p->ppid = result->kp_eproc.e_ppid;
+ p->starttime = result->kp_proc.p_starttime.tv_sec;
+ p->last_jiffies = result->kp_proc.p_cpticks;
+ //p_pctcpu
+
+ return 0;
+}
+#endif
+
+// returns the start time of a process (used with pid to identify a process)
+static int get_starttime(pid_t pid)
+{
+#ifdef __linux__
+ char file[20];
+ char buffer[1024];
+ sprintf(file, "/proc/%d/stat", pid);
+ FILE *fd = fopen(file, "r");
+ if (fd==NULL) return -1;
+ if (fgets(buffer, sizeof(buffer), fd) == NULL) return -1;
+ fclose(fd);
+ char *p = buffer;
+ p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
+ int sp = 20;
+ while (sp--)
+ p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
+ //start time of the process
+ int time = atoi(p+1);
+ return time;
+#elif defined __APPLE__
+ struct process proc;
+ get_proc_info(&proc, pid);
+ return proc.starttime;
+#endif
+}
+
+static int get_jiffies(struct process *proc) {
+#ifdef __linux__
+ FILE *f = fopen(proc->stat_file, "r");
+ if (f==NULL) return -1;
+ if (fgets(proc->buffer, sizeof(proc->buffer),f) == NULL) return -1;
+ fclose(f);
+ char *p = proc->buffer;
+ p = memchr(p+1,')', sizeof(proc->buffer) - (p-proc->buffer));
+ int sp = 12;
+ while (sp--)
+ p = memchr(p+1,' ',sizeof(proc->buffer) - (p-proc->buffer));
+ //user mode jiffies
+ int utime = atoi(p+1);
+ p = memchr(p+1,' ',sizeof(proc->buffer) - (p-proc->buffer));
+ //kernel mode jiffies
+ int ktime = atoi(p+1);
+ return utime+ktime;
+#elif defined __APPLE__
+ struct process proc2;
+ get_proc_info(&proc2, proc->pid);
+ return proc2.last_jiffies;
+#endif
+}
+
+//return t1-t2 in microseconds (no overflow checks, so better watch out!)
+static inline unsigned long timediff(const struct timeval *t1,const struct timeval *t2)
+{
+ return (t1->tv_sec - t2->tv_sec) * 1000000 + (t1->tv_usec - t2->tv_usec);
+}
+
+/*static int*/ int process_update(struct process *proc) {
+ //TODO: get any process statistic here
+ //check that starttime is not changed(?), update jiffies, parent, zombie status
+ return 0;
+}
+
+int process_init(struct process *proc, int pid)
+{
+ //general members
+ proc->pid = pid;
+ proc->starttime = get_starttime(pid);
+ proc->cpu_usage = 0;
+ memset(&(proc->last_sample), 0, sizeof(struct timeval));
+ proc->last_jiffies = -1;
+ //system dependent members
+#ifdef __linux__
+//TODO: delete these members for the sake of portability?
+ //test /proc file descriptor for reading
+ sprintf(proc->stat_file, "/proc/%d/stat", pid);
+ FILE *fd = fopen(proc->stat_file, "r");
+ if (fd == NULL) return 1;
+ fclose(fd);
+#endif
+ return 0;
+}
+
+//parameter in range 0-1
+#define ALFA 0.08
+
+int process_monitor(struct process *proc)
+{
+ int j = get_jiffies(proc);
+ if (j<0) return -1; //error retrieving jiffies count (maybe the process is dead)
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ if (proc->last_jiffies==-1) {
+ //store current time
+ proc->last_sample = now;
+ //store current jiffies
+ proc->last_jiffies = j;
+ //it's the first sample, cannot figure out the cpu usage
+ proc->cpu_usage = -1;
+ return 0;
+ }
+ //time from previous sample (in ns)
+ long dt = timediff(&now, &(proc->last_sample));
+ //how many jiffies in dt?
+ double max_jiffies = dt * HZ / 1000000.0;
+ double sample = (j - proc->last_jiffies) / max_jiffies;
+ if (proc->cpu_usage == -1) {
+ //initialization
+ proc->cpu_usage = sample;
+ }
+ else {
+ //usage adjustment
+ proc->cpu_usage = (1-ALFA) * proc->cpu_usage + ALFA * sample;
+ }
+
+ //store current time
+ proc->last_sample = now;
+ //store current jiffies
+ proc->last_jiffies = j;
+
+ return 0;
+}
+
+int process_close(struct process *proc)
+{
+ if (kill(proc->pid,SIGCONT)!=0) {
+ fprintf(stderr,"Process %d is already dead!\n", proc->pid);
+ }
+ proc->pid = 0;
+ return 0;
+}
Un proyecto texto-plano.xyz