aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAngelo Marletta <angelo.marletta@gmail.com>2012-06-22 01:55:53 +0100
committerAngelo Marletta <angelo.marletta@gmail.com>2012-06-22 01:55:53 +0100
commite01adfd46264d634009f0c3fe1e0f5936afffbd1 (patch)
tree79006930ae2a27858a630a2a066e6a9b589a5724 /src
parenteccc7f8368982422fb15287be27bdd83567d0e8c (diff)
downloadcpulimit-e01adfd46264d634009f0c3fe1e0f5936afffbd1.tar.gz
cpulimit.c integrated with the new changes
Diffstat (limited to 'src')
-rw-r--r--src/Makefile13
-rw-r--r--src/cpulimit.c149
-rw-r--r--src/process_group.c93
-rw-r--r--src/process_group.h4
-rw-r--r--src/process_iterator_freebsd.c1
-rw-r--r--src/process_iterator_linux.c20
-rw-r--r--src/procutils.c469
7 files changed, 157 insertions, 592 deletions
diff --git a/src/Makefile b/src/Makefile
index e6e819f..86fbfbd 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,7 +1,6 @@
CC?=gcc
CFLAGS?=-Wall -g -D_GNU_SOURCE
TARGETS=cpulimit
-#LIBS=procutils.o list.o process_iterator.o
LIBS=list.o process_iterator.o process_group.o
UNAME := $(shell uname)
@@ -10,10 +9,10 @@ ifeq ($(UNAME), FreeBSD)
LIBS+=-lkvm
endif
-all:: $(LIBS)
+all:: $(TARGETS) $(LIBS)
-#cpulimit: cpulimit.c $(LIBS)
-# $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS)
+cpulimit: cpulimit.c $(LIBS)
+ $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS)
process_iterator.o: process_iterator.c process_iterator.h
$(CC) -c process_iterator.c $(CFLAGS)
@@ -24,12 +23,6 @@ list.o: list.c list.h
process_group.o: process_group.c process_group.h process_iterator.o list.o
$(CC) -c process_group.c $(CFLAGS)
-#process.o: process.c process.h
-# $(CC) -c process.c $(CFLAGS)
-
-#procutils.o: procutils.c procutils.h
-# $(CC) -c procutils.c $(CFLAGS)
-
clean:
rm -f *~ *.o $(TARGETS)
diff --git a/src/cpulimit.c b/src/cpulimit.c
index 6126c6b..394b132 100644
--- a/src/cpulimit.c
+++ b/src/cpulimit.c
@@ -61,8 +61,7 @@
#include <sys/resource.h>
#include <sys/wait.h>
-#include "process.h"
-#include "procutils.h"
+#include "process_group.h"
#include "list.h"
//some useful macro
@@ -83,7 +82,7 @@
/* GLOBAL VARIABLES */
//the "family"
-struct process_family pf;
+struct process_group pgroup;
//pid of cpulimit
pid_t cpulimit_pid;
//name of this program (maybe cpulimit...)
@@ -104,13 +103,11 @@ static void quit(int sig)
{
//let all the processes continue if stopped
struct list_node *node = NULL;
- for (node=pf.members.first; node!= NULL; node=node->next) {
+ for (node=pgroup.proclist->first; node!= NULL; node=node->next) {
struct process *p = (struct process*)(node->data);
kill(p->pid, SIGCONT);
- process_close(p);
}
- //free all the memory
- cleanup_process_family(&pf);
+ close_process_group(&pgroup);
//fix ^C little problem
printf("\r");
fflush(stdout);
@@ -168,22 +165,7 @@ static int get_ncpu() {
return ncpu;
}
-#ifdef __linux__
-
-#include <sys/vfs.h>
-
-static int check_proc()
-{
- struct statfs mnt;
- if (statfs("/proc", &mnt) < 0)
- return 0;
- if (mnt.f_type!=0x9fa0)
- return 0;
- return 1;
-}
-#endif
-
-void limit_process(pid_t pid, double limit, int ignore_children)
+void limit_process(pid_t pid, double limit, int include_children)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
@@ -209,39 +191,17 @@ void limit_process(pid_t pid, double limit, int ignore_children)
increase_priority();
//build the family
- create_process_family(&pf, pid);
- if (ignore_children) {
- //delete any process with a different pid than the father
- for (node=pf.members.first; node!=NULL; node=node->next) {
- struct process *proc = (struct process*)(node->data);
- if (proc->pid != pid)
- remove_process_from_family(&pf, proc->pid);
- }
- }
-
- if (!ignore_children && verbose) printf("Members in the family owned by %d: %d\n", pf.father, pf.members.count);
+ init_process_group(&pgroup, pid, include_children);
+
+ if (verbose) printf("Members in the process group owned by %d: %d\n", pgroup.target_pid, pgroup.proclist->count);
//rate at which we are keeping active the processes (range 0-1)
//1 means that the process are using all the twork slice
double workingrate = -1;
while(1) {
- if (!ignore_children && c%10==0) {
- //update the process family (checks only for new members)
- int new_children = update_process_family(&pf);
- if (verbose && new_children) {
- printf("%d new children processes detected (", new_children);
- int j;
- node = pf.members.last;
- for (j=0; j<new_children; j++) {
- printf("%d", ((struct process*)(node->data))->pid);
- if (j<new_children-1) printf(" ");
- node = node->previous;
- }
- printf(")\n");
- }
- }
+ update_process_group(&pgroup);
- if (pf.members.count==0) {
+ if (pgroup.proclist->count==0) {
if (verbose) printf("No more processes.\n");
break;
}
@@ -251,24 +211,12 @@ void limit_process(pid_t pid, double limit, int ignore_children)
double pcpu = -1;
//estimate how much the controlled processes are using the cpu in the working interval
- for (node=pf.members.first; node!=NULL; node=node->next) {
+ for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *proc = (struct process*)(node->data);
- if (proc->is_zombie) {
- //process is zombie, remove it from family
- fprintf(stderr,"Process %d is zombie!\n", proc->pid);
- remove_process_from_family(&pf, proc->pid);
- continue;
- }
- if (process_monitor(proc) != 0) {
- //process is dead, remove it from family
- if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
- remove_process_from_family(&pf, proc->pid);
- continue;
- }
- if (proc->cpu_usage<0) {
+ if (proc->cpu_usage < 0) {
continue;
}
- if (pcpu<0) pcpu = 0;
+ if (pcpu < 0) pcpu = 0;
pcpu += proc->cpu_usage;
}
@@ -277,52 +225,52 @@ void limit_process(pid_t pid, double limit, int ignore_children)
//it's the 1st cycle, initialize workingrate
pcpu = limit;
workingrate = limit;
- twork.tv_nsec = TIME_SLOT*limit*1000;
+ twork.tv_nsec = TIME_SLOT * limit * 1000;
}
else {
//adjust workingrate
workingrate = MIN(workingrate / pcpu * limit, 1);
- twork.tv_nsec = TIME_SLOT*1000*workingrate;
+ twork.tv_nsec = TIME_SLOT * 1000 * workingrate;
}
- tsleep.tv_nsec = TIME_SLOT*1000-twork.tv_nsec;
+ tsleep.tv_nsec = TIME_SLOT * 1000 - twork.tv_nsec;
if (verbose) {
if (c%200==0)
printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
if (c%10==0 && c>0)
- printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n",pcpu*100,twork.tv_nsec/1000,tsleep.tv_nsec/1000,workingrate*100);
+ printf("%0.2lf%%\t%6ld us\t%6ld us\t%0.2lf%%\n", pcpu*100, twork.tv_nsec/1000, tsleep.tv_nsec/1000, workingrate*100);
}
//resume processes
- for (node=pf.members.first; node!=NULL; node=node->next) {
+ for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGCONT)!=0) {
//process is dead, remove it from family
- if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
- remove_process_from_family(&pf, proc->pid);
+ if (verbose) fprintf(stderr, "Process %d dead!\n", proc->pid);
+ //remove_process_from_family(&pf, proc->pid);
}
}
//now processes are free to run (same working slice for all)
gettimeofday(&startwork, NULL);
- nanosleep(&twork,NULL);
+ nanosleep(&twork, NULL);
gettimeofday(&endwork, NULL);
- workingtime = timediff(&endwork,&startwork);
+ workingtime = timediff(&endwork, &startwork);
- long delay = workingtime-twork.tv_nsec/1000;
+ long delay = workingtime - twork.tv_nsec/1000;
if (c>0 && delay>10000) {
//delay is too much! signal to user?
//fprintf(stderr, "%d %ld us\n", c, delay);
}
if (tsleep.tv_nsec>0) {
- //stop only if tsleep>0, instead it's useless
- for (node=pf.members.first; node!=NULL; node=node->next) {
+ //stop only if tsleep>0
+ for (node = pgroup.proclist->first; node != NULL; node = node->next) {
struct process *proc = (struct process*)(node->data);
if (kill(proc->pid,SIGSTOP)!=0) {
//process is dead, remove it from family
if (verbose) fprintf(stderr,"Process %d dead!\n", proc->pid);
- remove_process_from_family(&pf, proc->pid);
+ //remove_process_from_family(&pf, proc->pid);
}
}
//now the processes are sleeping
@@ -330,7 +278,7 @@ void limit_process(pid_t pid, double limit, int ignore_children)
}
c++;
}
- cleanup_process_family(&pf);
+ close_process_group(&pgroup);
}
int main(int argc, char **argv) {
@@ -344,8 +292,8 @@ int main(int argc, char **argv) {
int ignore_children = 0;
//get program name
- char *p=(char*)memrchr(argv[0],(unsigned int)'/',strlen(argv[0]));
- program_name = p==NULL?argv[0]:(p+1);
+ char *p = (char*)memrchr(argv[0], (unsigned int)'/', strlen(argv[0]));
+ program_name = p==NULL ? argv[0] : (p+1);
//get current pid
cpulimit_pid = getpid();
//get cpu count
@@ -405,12 +353,12 @@ int main(int argc, char **argv) {
}
} while(next_option != -1);
- if (pid_ok && (pid<=1 || pid>=65536)) {
+ if (pid_ok && (pid <= 1 || pid >= 65536)) {
fprintf(stderr,"Error: Invalid value for argument PID\n");
print_usage(stderr, 1);
exit(1);
}
- if (pid!=0) {
+ if (pid != 0) {
lazy = 1;
}
@@ -419,14 +367,14 @@ int main(int argc, char **argv) {
print_usage(stderr, 1);
exit(1);
}
- double limit = perclimit/100.0;
+ double limit = perclimit / 100.0;
if (limit<0 || limit >NCPU) {
fprintf(stderr,"Error: limit must be in the range 0-%d00\n", NCPU);
print_usage(stderr, 1);
exit(1);
}
- int command_mode = optind<argc;
+ int command_mode = optind < argc;
if (exe_ok + pid_ok + command_mode == 0) {
fprintf(stderr,"Error: You must specify one target process, either by name, pid, or command line\n");
print_usage(stderr, 1);
@@ -446,19 +394,12 @@ int main(int argc, char **argv) {
//print the number of available cpu
if (verbose) printf("%d cpu detected\n", NCPU);
-#ifdef __linux__
- if (!check_proc()) {
- fprintf(stderr, "procfs is not mounted!\nAborting\n");
- exit(-2);
- }
-#endif
-
if (command_mode) {
int i;
//executable file
const char *cmd = argv[optind];
//command line arguments
- char **cmd_args = (char**)malloc((argc-optind+1)*sizeof(char*));
+ char **cmd_args = (char**)malloc((argc-optind + 1) * sizeof(char*));
if (cmd_args==NULL) exit(2);
for (i=0; i<argc-optind; i++) {
cmd_args[i] = argv[i+optind];
@@ -477,7 +418,14 @@ int main(int argc, char **argv) {
if (child < 0) {
exit(EXIT_FAILURE);
}
- else if (child > 0) {
+ else if (child == 0) {
+ //target process code
+ int ret = execvp(cmd, cmd_args);
+ //if we are here there was an error, show it
+ perror("Error");
+ exit(ret);
+ }
+ else {
//parent code
free(cmd_args);
int limiter = fork();
@@ -504,13 +452,6 @@ int main(int argc, char **argv) {
exit(0);
}
}
- else {
- //target process code
- int ret = execvp(cmd, cmd_args);
- //if we are here there was an error, show it
- perror("Error");
- exit(ret);
- }
}
while(1) {
@@ -518,7 +459,7 @@ int main(int argc, char **argv) {
pid_t ret = 0;
if (pid_ok) {
//search by pid
- ret = look_for_process_by_pid(pid);
+ ret = find_process_by_pid(pid);
if (ret == 0) {
printf("No process found\n");
}
@@ -528,7 +469,7 @@ int main(int argc, char **argv) {
}
else {
//search by file or path name
- ret = look_for_process_by_name(exe);
+ ret = find_process_by_name(exe);
if (ret == 0) {
printf("No process found\n");
}
@@ -541,7 +482,7 @@ int main(int argc, char **argv) {
}
if (ret > 0) {
if (ret == cpulimit_pid) {
- printf("Process %d is cpulimit itself! Aborting to avoid deadlock\n", ret);
+ printf("Target process %d is cpulimit itself! Aborting because it makes no sense\n", ret);
exit(1);
}
printf("Process %d found\n", pid);
diff --git a/src/process_group.c b/src/process_group.c
index 318babb..71f180b 100644
--- a/src/process_group.c
+++ b/src/process_group.c
@@ -1,8 +1,8 @@
-#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
+#include <signal.h>
#include <assert.h>
@@ -10,6 +10,81 @@
#include "process_group.h"
#include "list.h"
+// look for a process by pid
+// search_pid : pid of the wanted process
+// return: pid of the found process, if successful
+// negative pid, if the process does not exist or if the signal fails
+int find_process_by_pid(pid_t pid)
+{
+ return (kill(pid,0)==0) ? pid : -pid;
+}
+
+// look for a process with a given name
+// process: the name of the wanted process. it can be an absolute path name to the executable file
+// or just the file name
+// return: pid of the found process, if it is found
+// 0, if it's not found
+// negative pid, if it is found but it's not possible to control it
+int find_process_by_name(const char *process_name)
+{
+ //whether the variable process_name is the absolute path or not
+ int is_absolute_path = process_name[0] == '/';
+ //flag indicating if the a process with given name was found
+ int found = 0;
+ pid_t pid = -1;
+
+ //process iterator
+ struct process_iterator it;
+ struct process proc;
+ struct process_filter filter;
+ filter.pid = 0;
+ filter.include_children = 0;
+ init_process_iterator(&it, &filter);
+ while (get_next_process(&it, &proc) != -1)
+ {
+ pid = proc.pid;
+ int size = strlen(proc.command);
+
+ found = 0;
+ if (is_absolute_path && strncmp(proc.command, process_name, size)==0 && size==strlen(process_name)) {
+ //process found
+ found = 1;
+ }
+ else {
+ //process found
+ if (strncmp(proc.command + size - strlen(process_name), process_name, strlen(process_name))==0) {
+ found = 1;
+ }
+ }
+ if (found==1) {
+ if (kill(pid,SIGCONT)==0) {
+ //process is ok!
+ break;
+ }
+ else {
+ //we don't have permission to send signal to that process
+ //so, don't exit from the loop and look for another one with the same name
+ found = -1;
+ }
+ }
+ }
+ if (close_process_iterator(&it) != 1) exit(1);
+ if (found == 1) {
+ //ok, the process was found
+ return pid;
+ }
+ else if (found == 0) {
+ //no process found
+ return 0;
+ }
+ else if (found == -1) {
+ //the process was found, but we haven't permission to control it
+ return -pid;
+ }
+ //this MUST NOT happen
+ exit(2);
+}
+
int init_process_group(struct process_group *pgroup, int target_pid, int include_children)
{
//hashtable initialization
@@ -19,6 +94,7 @@ int init_process_group(struct process_group *pgroup, int target_pid, int include
pgroup->proclist = (struct list*)malloc(sizeof(struct list));
init_list(pgroup->proclist, 4);
memset(&pgroup->last_update, 0, sizeof(pgroup->last_update));
+ update_process_group(pgroup);
return 0;
}
@@ -53,21 +129,23 @@ static inline unsigned long timediff(const struct timeval *t1,const struct timev
//parameter in range 0-1
#define ALFA 0.08
+#define MIN_DT 20
void update_process_group(struct process_group *pgroup)
{
struct process_iterator it;
struct process tmp_process;
struct process_filter filter;
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ //time elapsed from previous sample (in ms)
+ long dt = timediff(&now, &pgroup->last_update) / 1000;
filter.pid = pgroup->target_pid;
filter.include_children = pgroup->include_children;
init_process_iterator(&it, &filter);
clear_list(pgroup->proclist);
init_list(pgroup->proclist, 4);
- struct timeval now;
- gettimeofday(&now, NULL);
- //time elapsed from previous sample (in ms)
- long dt = timediff(&now, &pgroup->last_update) / 1000;
+
while (get_next_process(&it, &tmp_process) != -1)
{
// struct timeval t;
@@ -103,6 +181,8 @@ void update_process_group(struct process_group *pgroup)
assert(tmp_process.pid == p->pid);
assert(tmp_process.ppid == p->ppid);
assert(tmp_process.starttime == p->starttime);
+ add_elem(pgroup->proclist, p);
+ if (dt < MIN_DT) continue;
//process exists. update CPU usage
double sample = 1.0 * (tmp_process.cputime - p->cputime) / dt;
if (p->cpu_usage == -1) {
@@ -113,12 +193,11 @@ void update_process_group(struct process_group *pgroup)
//usage adjustment
p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample;
}
- p->cpu_usage = (1.0-ALFA) * p->cpu_usage + ALFA * sample;
p->cputime = tmp_process.cputime;
- add_elem(pgroup->proclist, p);
}
}
}
close_process_iterator(&it);
+ if (dt < MIN_DT) return;
pgroup->last_update = now;
}
diff --git a/src/process_group.h b/src/process_group.h
index f26d2cb..100711d 100644
--- a/src/process_group.h
+++ b/src/process_group.h
@@ -46,4 +46,8 @@ void update_process_group(struct process_group *pgroup);
int close_process_group(struct process_group *pgroup);
+int find_process_by_pid(pid_t pid);
+
+int find_process_by_name(const char *process_name);
+
#endif
diff --git a/src/process_iterator_freebsd.c b/src/process_iterator_freebsd.c
index fae671d..e840968 100644
--- a/src/process_iterator_freebsd.c
+++ b/src/process_iterator_freebsd.c
@@ -31,6 +31,7 @@ static void kproc2proc(struct kinfo_proc *kproc, struct process *proc)
proc->ppid = kproc->ki_ppid;
proc->cputime = kproc->ki_runtime / 1000;
proc->starttime = kproc->ki_start.tv_sec;
+ memcpy(proc->command, kproc->ki_comm, strlen(kproc->ki_comm));
}
static int get_single_process(pid_t pid, struct process *process)
diff --git a/src/process_iterator_linux.c b/src/process_iterator_linux.c
index da3fb07..a15be45 100644
--- a/src/process_iterator_linux.c
+++ b/src/process_iterator_linux.c
@@ -1,3 +1,5 @@
+#include <sys/vfs.h>
+
static int get_boot_time()
{
int uptime;
@@ -18,8 +20,22 @@ static int get_boot_time()
return now - uptime;
}
+static int check_proc()
+{
+ struct statfs mnt;
+ if (statfs("/proc", &mnt) < 0)
+ return 0;
+ if (mnt.f_type!=0x9fa0)
+ return 0;
+ return 1;
+}
+
int init_process_iterator(struct process_iterator *it, struct process_filter *filter)
{
+ if (!check_proc()) {
+ fprintf(stderr, "procfs is not mounted!\nAborting\n");
+ exit(-2);
+ }
//open a directory stream to /proc directory
if ((it->dip = opendir("/proc")) == NULL)
{
@@ -60,13 +76,13 @@ static int read_process_info(pid_t pid, struct process *p)
p->starttime = atoi(token) / sysconf(_SC_CLK_TCK);
//read command line
sprintf(exefile,"/proc/%d/cmdline", p->pid);
- fd = fopen(statfile, "r");
+ fd = fopen(exefile, "r");
if (fgets(buffer, sizeof(buffer), fd)==NULL) {
fclose(fd);
return -1;
}
fclose(fd);
- sscanf(buffer, "%s", (char*)&p->command);
+ sscanf(buffer, "%s", p->command);
return 0;
}
diff --git a/src/procutils.c b/src/procutils.c
deleted file mode 100644
index 7367196..0000000
--- a/src/procutils.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/**
- *
- * 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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
-
-#include "procutils.h"
-
-#ifdef __APPLE__
-#include <sys/sysctl.h>
-#include <errno.h>
-#endif
-
-#ifdef __FreeBSD__
-#include <kvm.h>
-#endif
-
-/* PROCESS STATISTICS FUNCTIONS */
-
-//deprecated
-// returns pid of the parent process
-static pid_t getppid_of(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 = 2;
- while (sp--)
- p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
- //pid of the parent process
- pid_t ppid = atoi(p+1);
- return ppid;
-#elif defined __APPLE__
- struct process p;
- get_proc_info(&p, pid);
- return p.ppid;
-#elif defined __FreeBSD__
-
-#endif
-}
-
-#ifdef __linux__
-// detects whether a process is a kernel thread or not
-static int is_kernel_thread(pid_t pid)
-{
- static char statfile[20];
- static char buffer[64];
- int ret;
- sprintf(statfile, "/proc/%d/statm", pid);
- FILE *fd = fopen(statfile, "r");
- if (fd==NULL) return -1;
- if (fgets(buffer, sizeof(buffer), fd)==NULL) return -1;
- ret = strncmp(buffer,"0 0 0",3)==0;
- fclose(fd);
- return ret;
-}
-#endif
-
-/* PID HASH FUNCTIONS */
-
-static int hash_process(struct process_family *f, struct process *p)
-{
- int ret;
- struct list **l = &(f->proctable[pid_hashfn(p->pid)]);
- if (*l == NULL) {
- //there is no process in this hashtable item
- //allocate the list
- *l = (struct list*)malloc(sizeof(struct list));
- init_list(*l, 4);
- add_elem(*l, p);
- ret = 0;
- f->count++;
- }
- else {
- //list already exists
- struct process *tmp = (struct process*)locate_elem(*l, p);
- if (tmp != NULL) {
- //update process info
- memcpy(tmp, p, sizeof(struct process));
- free(p);
- p = NULL;
- ret = 1;
- }
- else {
- //add new process
- add_elem(*l, p);
- ret = 0;
- f->count++;
- }
- }
- return ret;
-}
-
-static void unhash_process(struct process_family *f, pid_t pid) {
- //remove process from hashtable
- struct list **l = &(f->proctable[pid_hashfn(pid)]);
- if (*l == NULL)
- return; //nothing done
- struct list_node *node = locate_node(*l, &pid);
- if (node != NULL)
- destroy_node(*l, node);
- f->count--;
-}
-
-static struct process *seek_process(struct process_family *f, pid_t pid)
-{
- struct list **l = &(f->proctable[pid_hashfn(pid)]);
- return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
-}
-
-/* PROCESS ITERATOR STUFF */
-
-// creates an object that browse all running processes
-int init_process_iterator(struct process_iterator *i) {
-#ifdef __linux__
- //open a directory stream to /proc directory
- if ((i->dip = opendir("/proc")) == NULL) {
- perror("opendir");
- return -1;
- }
-#elif defined __APPLE__
-
- int err;
- struct kinfo_proc *result = NULL;
- size_t length;
- int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
-
- /* 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;
- }
- }
-
- i->procList = result;
- i->count = err == 0 ? length / sizeof *result : 0;
- i->c = 0;
-#elif defined __FreeBSD__
- kvm_t *kd;
- struct kinfo_proc *procs = NULL;
- char errbuf[_POSIX2_LINE_MAX];
- int count;
- /* Open the kvm interface, get a descriptor */
- if ((kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL) {
- /* fprintf(stderr, "kvm_open: %s\n", errbuf); */
- fprintf(stderr, "kvm_open: %s", errbuf);
- }
- /* Get the list of processes. */
- if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) {
- kvm_close(kd);
- /* fprintf(stderr, "kvm_getprocs: %s\n", kvm_geterr(kd)); */
- fprintf(stderr, "kvm_getprocs: %s", kvm_geterr(kd));
- }
-
-#endif
- i->current = (struct process*)calloc(1, sizeof(struct process));
- return 0;
-}
-
-int close_process_iterator(struct process_iterator *i) {
-#ifdef __linux__
- if (closedir(i->dip) == -1) {
- perror("closedir");
- return 1;
- }
-#elif defined __APPLE__
- //TODO
-#endif
- return 0;
-}
-
-// reads the next user process from /process
-// automatic closing if the end of the list is reached
-int read_next_process(struct process_iterator *i) {
-#ifdef __linux__
- pid_t pid = 0;
-//TODO read this to port to other systems: http://www.steve.org.uk/Reference/Unix/faq_8.html#SEC85
- //read in from /proc and seek for process dirs
- while ((i->dit = readdir(i->dip)) != NULL) {
- if(strtok(i->dit->d_name, "0123456789") != NULL)
- continue;
- pid = atoi(i->dit->d_name);
- if (is_kernel_thread(pid))
- continue;
- //return the first found process
- break;
- }
- if (pid == 0) {
- //no more processes
- closedir(i->dip);
- free(i->current);
- i->current = NULL;
- return -1;
- }
- //read the executable link
- char statfile[20];
- sprintf(statfile,"/proc/%d/cmdline",pid);
- FILE *fd = fopen(statfile, "r");
- if (fd == NULL) return -1;
- char buffer[1024];
- if (fgets(buffer, sizeof(buffer), fd)==NULL) return -2;
- fclose(fd);
- sscanf(buffer, "%s", (char*)&i->current->command);
- i->current->pid = pid;
-
-#elif defined __APPLE__
- if (i->c >= i->count) {
- //no more processes
- free(i->procList);
- i->procList = NULL;
- free(i->current);
- i->current = NULL;
- return -1;
- }
- i->current->pid = i->procList[i->c].kp_proc.p_pid;
- strncpy(i->current->command, i->procList[i->c].kp_proc.p_comm, MAXCOMLEN);
-printf("%d %d %s\n", i->c, i->current->pid, i->current->command);//i->procList[i->c].kp_proc.p_comm);
-//printf("%d %d %s\n", i->c, i->current->pid, i->proc[i->c].kp_proc.p_comm);
- i->c++;
-#endif
- return 0;
-}
-
-/* PUBLIC FUNCTIONS */
-
-// search for all the processes derived from father and stores them
-// in the process family struct
-int create_process_family(struct process_family *f, pid_t father)
-{
- //process list initialization (4 bytes key)
- init_list(&(f->members), 4);
- //hashtable initialization
- memset(&(f->proctable), 0, sizeof(f->proctable));
- f->count = 0;
- f->father = father;
- //process iterator
- struct process_iterator iter;
- init_process_iterator(&iter);
- int pid = 0;
- while (read_next_process(&iter)==0) {
- pid = iter.current->pid;
- //check if process belongs to the family
- int ppid = pid;
- //TODO: optimize adding also these parents, and continue if process is already present
- while(ppid!=1 && ppid!=father) {
- ppid = getppid_of(ppid);
- }
- //allocate process descriptor
- struct process *p = (struct process*)calloc(1, sizeof(struct process));
- //init process
- process_init(p, pid);
- if (ppid==1) {
- //the init process
- p->member = 0;
- }
- else if (pid != getpid()) {
- //add to members (but exclude the current cpulimit process!)
- p->member = 1;
- add_elem(&(f->members), p);
- }
- //add to hashtable
- hash_process(f, p);
- }
- return 0;
-}
-
-// checks if there are new processes born in the specified family
-// if any they are added to the members list
-// the number of new born processes is returned
-int update_process_family(struct process_family *f)
-{
- int ret = 0;
- //process iterator
- struct process_iterator iter;
- init_process_iterator(&iter);
- int pid = 0;
- while (read_next_process(&iter)==0) {
- pid = iter.current->pid;
- struct process *newp = seek_process(f, pid);
- if (newp != NULL) continue; //already known //TODO: what if newp is a new process with the same PID??
- //the process is new, check if it belongs to the family
- int ppid = getppid_of(pid);
- //search the youngest known ancestor of the process
- struct process *ancestor = NULL;
- while((ancestor=seek_process(f, ppid))==NULL) {
- ppid = getppid_of(ppid);
- }
- if (ancestor == NULL) {
- //this should never happen! if does, find and correct the bug
- fprintf(stderr, "Fatal bug! Process %d is without parent\n", pid);
- exit(1);
- }
- //allocate and insert the process
- struct process *p = (struct process*)calloc(1, sizeof(struct process));
- //init process
- process_init(p, pid);
- if (ancestor->member) {
- //add to members
- p->member = 1;
- add_elem(&(f->members), p);
- ret++;
- }
- else {
- //not a member
- p->member = 0;
- }
- //add to hashtable
- hash_process(f, p);
- }
- return ret;
-}
-
-// removes a process from the family by its pid
-void remove_process_from_family(struct process_family *f, pid_t pid)
-{
- struct list_node *node = locate_node(&(f->members), &pid);
- if (node != NULL) {
-// struct process *p = (struct process*)(node->data);
-// free(p->history);
-// p->history = NULL;
- delete_node(&(f->members), node);
- }
- unhash_process(f, pid);
-}
-
-// free the heap memory used by a process family
-void cleanup_process_family(struct process_family *f)
-{
- int i;
- int size = sizeof(f->proctable) / sizeof(struct process*);
- for (i=0; i<size; i++) {
- if (f->proctable[i] != NULL) {
- //free() history for each process
- struct list_node *node = NULL;
- for (node=f->proctable[i]->first; node!=NULL; node=node->next) {
-// struct process *p = (struct process*)(node->data);
-// free(p->history);
-// p->history = NULL;
- }
- destroy_list(f->proctable[i]);
- free(f->proctable[i]);
- f->proctable[i] = NULL;
- }
- }
- flush_list(&(f->members));
- f->count = 0;
- f->father = 0;
-}
-
-// look for a process by pid
-// search_pid : pid of the wanted process
-// return: pid of the found process, if successful
-// negative pid, if the process does not exist or if the signal fails
-int look_for_process_by_pid(pid_t pid)
-{
- return (kill(pid,0)==0) ? pid : -pid;
-}
-
-// look for a process with a given name
-// process: the name of the wanted process. it can be an absolute path name to the executable file
-// or just the file name
-// return: pid of the found process, if it is found
-// 0, if it's not found
-// negative pid, if it is found but it's not possible to control it
-int look_for_process_by_name(const char *process_name)
-{
- //whether the variable process_name is the absolute path or not
- int is_absolute_path = process_name[0] == '/';
- //flag indicating if the a process with given name was found
- int found = 0;
-
- //process iterator
- struct process_iterator iter;
- init_process_iterator(&iter);
- pid_t pid = 0;
-
- while (read_next_process(&iter)==0) {
- pid = iter.current->pid;
-
- int size = strlen(iter.current->command);
-
- found = 0;
- if (is_absolute_path && strncmp(iter.current->command, process_name, size)==0 && size==strlen(process_name)) {
- //process found
- found = 1;
- }
- else {
- //process found
- if (strncmp(iter.current->command + size - strlen(process_name), process_name, strlen(process_name))==0) {
- found = 1;
- }
- }
- if (found==1) {
- if (kill(pid,SIGCONT)==0) {
- //process is ok!
- break;
- }
- else {
- //we don't have permission to send signal to that process
- //so, don't exit from the loop and look for another one with the same name
- found = -1;
- }
- }
- }
- if (close_process_iterator(&iter) != 1) exit(1);
- if (found == 1) {
- //ok, the process was found
- return pid;
- }
- else if (found == 0) {
- //no process found
- return 0;
- }
- else if (found == -1) {
- //the process was found, but we haven't permission to control it
- return -pid;
- }
- //this MUST NOT happen
- exit(2);
-}
-
Un proyecto texto-plano.xyz