aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b>2008-08-29 21:45:04 +0000
committerbhackerozzo <bhackerozzo@3b445381-d045-0410-9223-e17ecdb95f4b>2008-08-29 21:45:04 +0000
commit794f9410a52b21e8bcedeecedc7f8737daee5418 (patch)
treed6a8a5f585110b64167fe4f38d1de248a657c3b3
parent83bce718d6f49760463e973759ab575f8573f297 (diff)
downloadcpulimit-794f9410a52b21e8bcedeecedc7f8737daee5418.tar.gz
experimental support for OS X
-rw-r--r--Makefile13
-rw-r--r--cpulimit.c57
-rw-r--r--process.c15
-rw-r--r--process.h6
-rw-r--r--procutils.c106
-rw-r--r--procutils.h25
-rw-r--r--tools/jiffy.c69
-rw-r--r--tools/loop.c3
-rw-r--r--tools/ptest.c59
9 files changed, 300 insertions, 53 deletions
diff --git a/Makefile b/Makefile
index 6f820cf..4492d9d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,17 @@
CC?=gcc
CFLAGS?=-Wall -O2
-CFLAGS+=-D_GNU_SOURCE
-TARGETS=cpulimit ptest
+TARGETS=cpulimit
LIBS=process.o procutils.o list.o
+OSXFLAGS=-framework Carbon
+
+ifeq ($(OS), APPLE)
+CFLAGS+=-framework Carbon
+endif
all:: $(TARGETS)
cpulimit: cpulimit.c $(LIBS)
- $(CC) -o cpulimit cpulimit.c $(LIBS) -lrt $(CFLAGS)
+ $(CC) -o cpulimit cpulimit.c $(LIBS) $(CFLAGS)
process.o: process.c process.h
$(CC) -c process.c $(CFLAGS)
@@ -18,9 +22,6 @@ procutils.o: procutils.c procutils.h
list.o: list.c list.h
$(CC) -c list.c $(CFLAGS)
-ptest: ptest.c
- $(CC) -o ptest ptest.c -lrt $(CFLAGS)
-
clean:
rm -f *~ *.o $(TARGETS)
diff --git a/cpulimit.c b/cpulimit.c
index e4a7502..2c95850 100644
--- a/cpulimit.c
+++ b/cpulimit.c
@@ -46,24 +46,29 @@
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
-#include <sys/time.h>
#include <unistd.h>
-#include <sys/types.h>
#include <signal.h>
-#include <sys/resource.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
#include "process.h"
#include "procutils.h"
#include "list.h"
//some useful macro
+#ifndef MIN
#define MIN(a,b) (a<b?a:b)
+#endif
+#ifndef MAX
#define MAX(a,b) (a>b?a:b)
-#define print_caption() printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n")
+#endif
//control time slot in microseconds
//each slot is splitted in a working slice and a sleeping slice
@@ -76,7 +81,7 @@
//the "family"
struct process_family pf;
//pid of cpulimit
-int cpulimit_pid;
+pid_t cpulimit_pid;
//name of this program (maybe cpulimit...)
char *program_name;
@@ -87,11 +92,28 @@ int verbose = 0;
//lazy mode (exits if there is no process)
int lazy = 0;
+void *memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *start=s,*end=s;
+
+ end+=n-1;
+
+ while(end>=start) {
+ if(*end==c)
+ return (void *)end;
+ else
+ end--;
+ }
+
+ return NULL;
+}
+
//how many cpu do we have?
int get_cpu_count()
{
- FILE *fd;
int cpu_count = 0;
+#ifdef __GNUC__
+ FILE *fd;
char line[100];
fd = fopen("/proc/stat", "r");
if (fd < 0)
@@ -102,6 +124,11 @@ int get_cpu_count()
}
fclose(fd);
return cpu_count - 1;
+#elif defined __APPLE__
+//TODO: test sysconf(_SC_NPROCESSORS_ONLN), sysconf(_SC_NPROCESSORS_CONF)
+ if (sysctlbyname("hw.ncpu",&cpu_count,sizeof(int),NULL,0)) return 1;
+ return cpu_count;
+#endif
}
//return t1-t2 in microseconds (no overflow checks, so better watch out!)
@@ -146,7 +173,7 @@ void print_usage(FILE *stream, int exit_code)
exit(exit_code);
}
-void limit_process(int pid, double limit)
+void limit_process(pid_t pid, double limit)
{
//slice of the slot in which the process is allowed to run
struct timespec twork;
@@ -177,7 +204,8 @@ void limit_process(int pid, double limit)
while(1) {
- if (i%200==0 && verbose) print_caption();
+ if (i%200==0 && verbose)
+ printf("\n%%CPU\twork quantum\tsleep quantum\tactive rate\n");
if (i%10==0) {
//update the process family (checks only for new members)
@@ -327,7 +355,7 @@ int main(int argc, char **argv) {
int exe_ok = 0;
int pid_ok = 0;
int limit_ok = 0;
- int pid = 0;
+ pid_t pid = 0;
//parse arguments
int next_option;
@@ -447,11 +475,11 @@ int main(int argc, char **argv) {
cmd_args[i] = NULL;
if (verbose) {
- printf("Running command: %s ", cmd);
+ printf("Running command: '%s", cmd);
for (i=0; i<argc-optind-1; i++) {
- printf("%s ", cmd_args[i]);
+ printf(" %s", cmd_args[i]);
}
- printf("\n");
+ printf("'\n");
}
int child = fork();
@@ -469,7 +497,8 @@ int main(int argc, char **argv) {
else {
//child code
int ret = execvp(cmd, cmd_args);
- //if we are here there was a fatal ERROR!
+ //if we are here there was an error, show it
+ perror("Error");
exit(ret);
}
return 0;
@@ -477,7 +506,7 @@ int main(int argc, char **argv) {
while(!lazy) {
//look for the target process..or wait for it
- int ret = 0;
+ pid_t ret = 0;
if (pid_ok) {
//search by pid
ret = look_for_process_by_pid(pid);
diff --git a/process.c b/process.c
index f634aa3..e570ad6 100644
--- a/process.c
+++ b/process.c
@@ -23,13 +23,19 @@
#include "process.h"
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
int process_init(struct process_history *proc, int pid)
{
+#ifdef __GNUC__
//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
//init properties
proc->pid = pid;
proc->cpu_usage = 0;
@@ -45,6 +51,7 @@ static inline unsigned long timediff(const struct timeval *t1,const struct timev
}
static int get_jiffies(struct process_history *proc) {
+#ifdef __GNUC__
FILE *f = fopen(proc->stat_file, "r");
if (f==NULL) return -1;
fgets(proc->buffer, sizeof(proc->buffer),f);
@@ -60,8 +67,16 @@ static int get_jiffies(struct process_history *proc) {
//kernel mode jiffies
int ktime = atoi(p+1);
return utime+ktime;
+#elif defined __APPLE__
+ ProcessSerialNumber psn;
+ ProcessInfoRec info;
+ if (GetProcessForPID(proc->pid, &psn)) return -1;
+ if (GetProcessInformation(&psn, &info)) return -1;
+ return info.processActiveTime;
+#endif
}
+//parameter in range 0-1
#define ALFA 0.08
int process_monitor(struct process_history *proc)
diff --git a/process.h b/process.h
index 12c9fc2..a9497fa 100644
--- a/process.h
+++ b/process.h
@@ -38,11 +38,13 @@
//process descriptor
struct process_history {
//the PID of the process
- int pid;
+ pid_t pid;
+#ifdef __GNUC__
//name of /proc/PID/stat file
char stat_file[20];
//read buffer for /proc filesystem
char buffer[1024];
+#endif
//timestamp when last_j and cpu_usage was calculated
struct timeval last_sample;
//total number of jiffies used by the process at time last_sample
@@ -51,7 +53,7 @@ struct process_history {
double cpu_usage;
};
-int process_init(struct process_history *proc, int pid);
+int process_init(struct process_history *proc, pid_t pid);
int process_monitor(struct process_history *proc);
diff --git a/procutils.c b/procutils.c
index 989c555..e7d4d89 100644
--- a/procutils.c
+++ b/procutils.c
@@ -25,8 +25,9 @@
/* PROCESS STATISTICS FUNCTIONS */
// returns pid of the parent process
-static int getppid_of(int pid)
+static pid_t getppid_of(pid_t pid)
{
+#ifdef __GNUC__
char file[20];
char buffer[1024];
sprintf(file, "/proc/%d/stat", pid);
@@ -40,13 +41,25 @@ static int getppid_of(int pid)
while (sp--)
p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
//pid of the parent process
- int ppid = atoi(p+1);
+ pid_t ppid = atoi(p+1);
return ppid;
+#elif defined __APPLE__
+ ProcessSerialNumber psn_child;
+ ProcessInfoRec info_child;
+ pid_t ppid;
+ memset(&info_child, 0, sizeof(ProcessInfoRec));
+ info_child.processInfoLength = sizeof(ProcessInfoRec);
+ if (GetProcessForPID(pid, &psn_child)) return -1;
+ if (GetProcessInformation(&psn_child, &info_child)) return -1;
+ if (GetProcessPID (&(info_child.processLauncher), &ppid)) return -1;
+ return ppid;
+#endif
}
// returns the start time of a process (used with pid to identify a process)
-static int get_starttime(int pid)
+static int get_starttime(pid_t pid)
{
+#ifdef __GNUC__
char file[20];
char buffer[1024];
sprintf(file, "/proc/%d/stat", pid);
@@ -62,11 +75,21 @@ static int get_starttime(int pid)
//start time of the process
int time = atoi(p+1);
return time;
+#elif defined __APPLE__
+ ProcessSerialNumber psn;
+ ProcessInfoRec info;
+ memset(&info, 0, sizeof(ProcessInfoRec));
+ info.processInfoLength = sizeof(ProcessInfoRec);
+ if (GetProcessForPID(pid, &psn)) return -1;
+ if (GetProcessInformation(&psn, &info)) return -1;
+ return info.processLaunchDate;
+#endif
}
// detects whether a process is a kernel thread or not
-static int is_kernel_thread(int pid)
+static int is_kernel_thread(pid_t pid)
{
+#ifdef __GNUC__
static char statfile[20];
static char buffer[64];
int ret;
@@ -77,10 +100,14 @@ static int is_kernel_thread(int pid)
ret = strncmp(buffer,"0 0 0",3)==0;
fclose(fd);
return ret;
+#elif defined __APPLE__
+ return 0;
+#endif
}
// returns 1 if pid is a user process, 0 otherwise
-static int process_exists(int pid) {
+static int process_exists(pid_t pid) {
+#ifdef __GNUC__
static char statfile[20];
static char buffer[64];
int ret;
@@ -91,6 +118,10 @@ static int process_exists(int pid) {
ret = strncmp(buffer,"0 0 0",3)!=0;
fclose(fd);
return ret;
+#elif defined __APPLE__
+ ProcessSerialNumber psn;
+ return !GetProcessForPID(pid, &psn);
+#endif
}
/* PID HASH FUNCTIONS */
@@ -112,7 +143,6 @@ static int hash_process(struct process_family *f, struct process *p)
//list already exists
struct process *tmp = (struct process*)locate_elem(*l, p);
if (tmp != NULL) {
- //TODO: should free() something? tmp? p?
//update process info
memcpy(tmp, p, sizeof(struct process));
free(p);
@@ -129,7 +159,7 @@ static int hash_process(struct process_family *f, struct process *p)
return ret;
}
-static void unhash_process(struct process_family *f, int pid) {
+static void unhash_process(struct process_family *f, pid_t pid) {
//remove process from hashtable
struct list **l = &(f->hashtable[pid_hashfn(pid)]);
if (*l == NULL)
@@ -140,41 +170,42 @@ static void unhash_process(struct process_family *f, int pid) {
f->count--;
}
-static struct process *seek_process(struct process_family *f, int pid)
+static struct process *seek_process(struct process_family *f, pid_t pid)
{
struct list **l = &(f->hashtable[pid_hashfn(pid)]);
return (*l != NULL) ? (struct process*)locate_elem(*l, &pid) : NULL;
}
/*
-static int is_member(struct process_family *f, int pid) {
+static int is_member(struct process_family *f, pid_t pid) {
struct process *p = seek_process(f, pid);
return (p!=NULL && p->member);
}
-
-static int exists(struct process_family *f, int pid) {
- struct process *p = seek_process(f, pid);
- return p!=NULL;
-}
*/
/* PROCESS ITERATOR STUFF */
// creates an object that browse all running processes
static int init_process_iterator(struct process_iterator *i) {
+#ifdef __GNUC__
//open a directory stream to /proc directory
if ((i->dip = opendir("/proc")) == NULL) {
perror("opendir");
return -1;
}
+#elif defined __APPLE__
+ i->psn.highLongOfPSN = kNoProcess;
+ i->psn.lowLongOfPSN = kNoProcess;
+#endif
return 0;
}
// reads the next user process from /process
// automatic closing if the end of the list is reached
static int read_next_process(struct process_iterator *i) {
+ pid_t pid = 0;
+#ifdef __GNUC__
//read in from /proc and seek for process dirs
- int pid = 0;
while ((i->dit = readdir(i->dip)) != NULL) {
pid = atoi(i->dit->d_name);
if (pid<=0 || is_kernel_thread(pid))
@@ -186,6 +217,13 @@ static int read_next_process(struct process_iterator *i) {
//no more processes, release resources
closedir(i->dip);
}
+#elif defined __APPLE__
+ ProcessInfoRec info;
+ memset(&info, 0, sizeof(ProcessInfoRec));
+ info.processInfoLength = sizeof(ProcessInfoRec);
+ if (GetNextProcess(&i->psn)) return 0;
+ GetProcessPID(&(i->psn), &pid);
+#endif
return pid;
}
@@ -193,7 +231,7 @@ static int read_next_process(struct process_iterator *i) {
// searches for all the processes derived from father and stores them
// in the process family struct
-int create_process_family(struct process_family *f, int father)
+int create_process_family(struct process_family *f, pid_t father)
{
//process list initialization (4 bytes key)
init_list(&(f->members), 4);
@@ -283,7 +321,7 @@ int update_process_family(struct process_family *f)
}
// removes a process from the family by its pid
-void remove_process_from_family(struct process_family *f, int 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) {
@@ -324,7 +362,7 @@ void cleanup_process_family(struct process_family *f)
// 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_pid(int pid)
+int look_for_process_by_pid(pid_t pid)
{
if (process_exists(pid))
return (kill(pid,SIGCONT)==0) ? pid : -pid;
@@ -337,34 +375,48 @@ int look_for_process_by_pid(int pid)
// 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)
+int look_for_process_by_name(const char *process_name)
{
//the name of /proc/pid/exe symbolic link pointing to the executable file
char exelink[20];
//the name of the executable file
- char exepath[PATH_MAX+1];
- //whether the variable process is the absolute path or not
- int is_absolute_path = process[0] == '/';
+ char *exepath = malloc((PATH_MAX+1) * sizeof(char));
+ //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);
- int pid = 0;
+ pid_t pid = 0;
+#ifdef __APPLE__
+ ProcessSerialNumber psn;
+ ProcessInfoRec info;
+ memset(&info, 0, sizeof(ProcessInfoRec));
+ info_child.processInfoLength = sizeof(ProcessInfoRec);
+ info.processName = (char*)malloc(64*sizeof(char));
+#endif
while ((pid = read_next_process(&iter))) {
+#ifdef __GNUC__
//read the executable link
sprintf(exelink,"/proc/%d/exe",pid);
int size = readlink(exelink, exepath, sizeof(exepath));
+#elif defined __APPLE__
+ //get the executable file name
+ if (GetProcessForPID(pid, &psn)) return -1;
+ if (GetProcessInformation(&psn, &info)) return -1;
+ int size = strlen(info.processName);
+#endif
if (size>0) {
found = 0;
- if (is_absolute_path && strncmp(exepath, process, size)==0 && size==strlen(process)) {
+ if (is_absolute_path && strncmp(exepath, process_name, size)==0 && size==strlen(process_name)) {
//process found
found = 1;
}
else {
//process found
- if (strncmp(exepath + size - strlen(process), process, strlen(process))==0) {
+ if (strncmp(exepath + size - strlen(process_name), process_name, strlen(process_name))==0) {
found = 1;
}
}
@@ -381,6 +433,10 @@ int look_for_process_by_name(const char *process)
}
}
}
+ free(exepath);
+#ifdef __APPLE__
+ free(info.processName);
+#endif
if (found == 1) {
//ok, the process was found
return pid;
diff --git a/procutils.h b/procutils.h
index 8a1deb2..d0d2f3e 100644
--- a/procutils.h
+++ b/procutils.h
@@ -30,16 +30,25 @@
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
+#include <limits.h>
#include "list.h"
#include "process.h"
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
#define PIDHASH_SZ 1024
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
// a hierarchy of processes
struct process_family {
//the (god)father of the process family
- int father;
+ pid_t father;
//process list (father process is the first element)
//elements are struct process
struct list members;
@@ -53,7 +62,7 @@ struct process_family {
// process descriptor
struct process {
//pid of the process
- int pid;
+ pid_t pid;
//start time
int starttime;
//is member of the family?
@@ -63,13 +72,17 @@ struct process {
// object to enumerate running processes
struct process_iterator {
+#ifdef __GNUC__
DIR *dip;
- struct dirent *dit;
+ struct dirent *dit;
+#elif defined __APPLE__
+ ProcessSerialNumber psn;
+#endif
};
// searches for all the processes derived from father and stores them
// in the process family struct
-int create_process_family(struct process_family *f, int father);
+int create_process_family(struct process_family *f, pid_t father);
// checks if there are new processes born in the specified family
// if any they are added to the members list
@@ -77,7 +90,7 @@ int create_process_family(struct process_family *f, int father);
int update_process_family(struct process_family *f);
// removes a process from the family by its pid
-void remove_process_from_family(struct process_family *f, int pid);
+void remove_process_from_family(struct process_family *f, pid_t pid);
// free the heap memory used by a process family
void cleanup_process_family(struct process_family *f);
@@ -88,6 +101,6 @@ int look_for_process_by_name(const char *process);
// searches a process given its pid
// returns the pid, or 0 if it's not found
-int look_for_process_by_pid(int pid);
+int look_for_process_by_pid(pid_t pid);
#endif
diff --git a/tools/jiffy.c b/tools/jiffy.c
new file mode 100644
index 0000000..298f300
--- /dev/null
+++ b/tools/jiffy.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <Carbon/Carbon.h>
+#endif
+
+static int get_jiffies(pid_t pid) {
+#ifdef __GNUC__
+ char buffer[1024];
+ char stat_file[32];
+ sprintf(stat_file, "/proc/%d/stat", pid);
+ FILE *f = fopen(stat_file, "r");
+ if (f==NULL) return -1;
+ fgets(buffer, sizeof(buffer),f);
+ fclose(f);
+ char *p = buffer;
+ p = memchr(p+1,')', sizeof(buffer) - (p-buffer));
+ int sp = 12;
+ while (sp--)
+ p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
+ //user mode jiffies
+ int utime = atoi(p+1);
+ p = memchr(p+1,' ',sizeof(buffer) - (p-buffer));
+ //kernel mode jiffies
+ int ktime = atoi(p+1);
+ return utime+ktime;
+#elif defined __APPLE__
+ ProcessSerialNumber psn;
+ ProcessInfoRec info;
+ if (GetProcessForPID(pid, &psn)) return -1;
+ if (GetProcessInformation(&psn, &info)) return -1;
+ return info.processActiveTime;
+#endif
+}
+
+struct timeval timeval_diff(struct timeval *tv1, struct timeval *tv2)
+{
+ struct timeval diff;
+ diff.tv_sec = tv2->tv_sec - tv1->tv_sec;
+ diff.tv_usec = tv2->tv_usec - tv1->tv_usec;
+ if (diff.tv_usec < 0) {
+ diff.tv_sec--;
+ diff.tv_usec += 1000000;
+ }
+ return diff;
+}
+
+int main() {
+ struct timeval start, now, diff;
+ int i,j;
+ int pid = getpid();
+ gettimeofday(&start, NULL);
+ printf("time j HZ jiffy time\n");
+ while(1) {
+ for(i=0;i<100000;i++)
+ for(j=0;j<10000;j++);
+ int j = get_jiffies(pid);
+ if (j<0) exit(-1);
+ gettimeofday(&now, NULL);
+ diff = timeval_diff(&start, &now);
+ double d = diff.tv_sec + diff.tv_usec * 1e-6;
+ printf("%lf %d %lf %lf ms\n", d, j, j/d, 1000*d/j);
+ }
+ exit(0);
+}
diff --git a/tools/loop.c b/tools/loop.c
new file mode 100644
index 0000000..c9280d2
--- /dev/null
+++ b/tools/loop.c
@@ -0,0 +1,3 @@
+int main() {
+ while(1);
+}
diff --git a/tools/ptest.c b/tools/ptest.c
new file mode 100644
index 0000000..ee85a2a
--- /dev/null
+++ b/tools/ptest.c
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define N 8
+
+//simple program to test cpulimit
+int main()
+{
+ printf("Parent: PID %d\n", getpid());
+ getchar();
+ sleep(1);
+ while(1);
+ int i;
+ int children[N];
+ for (i=0;i<N;i++) {
+ int pid = fork();
+ if (pid>0) {
+ //parent code
+ children[i] = pid;
+ printf("Child %d created\n", pid);
+ }
+ else if (pid==0) {
+ while(1);
+ //child code
+// while(1) {
+ //random generator initialization
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ srandom(t.tv_sec + t.tv_usec + getpid());
+ int loop = random() % 1000000;
+ printf("start\n");
+ int i,j;
+ for (i=0;i<1000;i++)
+ for (j=0;j<loop;j++);
+ printf("stop\n");
+ int time = random() % 10000000;
+ // printf("Child %d wait %d\n", getpid(), time);
+ usleep(time);
+ printf("Child %d terminated\n", getpid());
+// }
+ exit(0);
+ }
+ else {
+ fprintf(stderr, "fork() failed!\n");
+ }
+ }
+ for (i=0;i<N;i++) {
+ int status;
+ waitpid(children[i], &status, 0);
+ }
+ sleep(1);
+ return 0;
+}
Un proyecto texto-plano.xyz