From 2e2354db1c8480499987afbc4e14edaa0fa283da Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 2 Jul 2012 01:43:48 +0200 Subject: Fix: replace missing memrchr function on OS X --- src/cpulimit.c | 4 ++++ src/memrchr.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/memrchr.c diff --git a/src/cpulimit.c b/src/cpulimit.c index e7d5309..8332468 100644 --- a/src/cpulimit.c +++ b/src/cpulimit.c @@ -46,6 +46,10 @@ #include "process_group.h" #include "list.h" +#ifdef __APPLE__ +#include "memrchr.c" +#endif + //some useful macro #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) diff --git a/src/memrchr.c b/src/memrchr.c new file mode 100644 index 0000000..35e07de --- /dev/null +++ b/src/memrchr.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2007 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +/* + * Reverse memchr() + * Find the last occurrence of 'c' in the buffer 's' of size 'n'. + */ +void * +memrchr(s, c, n) + const void *s; + int c; + size_t n; +{ + const unsigned char *cp; + + if (n != 0) { + cp = (unsigned char *)s + n; + do { + if (*(--cp) == (unsigned char)c) + return((void *)cp); + } while (--n != 0); + } + return((void *)0); +} -- cgit v1.2.3 From 9c17a0c4d02dc8f39a2cfd440706f91133311fad Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 2 Jul 2012 01:45:28 +0200 Subject: Completed the iterator for OSX. --- src/memrchr.c | 2 - src/process_iterator.c | 2 + src/process_iterator.h | 4 +- src/process_iterator_apple.c | 146 +++++++++++++++++++++++-------------------- 4 files changed, 84 insertions(+), 70 deletions(-) diff --git a/src/memrchr.c b/src/memrchr.c index 35e07de..ba788f5 100644 --- a/src/memrchr.c +++ b/src/memrchr.c @@ -15,8 +15,6 @@ */ #include -#include -#include /* * Reverse memchr() diff --git a/src/process_iterator.c b/src/process_iterator.c index 165f420..8b4019d 100644 --- a/src/process_iterator.c +++ b/src/process_iterator.c @@ -22,7 +22,9 @@ #include #include #include +#ifndef __APPLE__ #include +#endif #include #include "process_iterator.h" diff --git a/src/process_iterator.h b/src/process_iterator.h index ecbe995..70520b6 100644 --- a/src/process_iterator.h +++ b/src/process_iterator.h @@ -81,7 +81,9 @@ struct process_iterator { int count; int i; #elif defined __APPLE__ - struct kinfo_proc *proclist; + int i; + int count; + int *pidlist; #endif struct process_filter *filter; }; diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index d7aa5f3..1f98bf2 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -19,80 +19,92 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -int init_process_iterator(struct process_iterator *it) { +#include +#include +#include + +int init_process_iterator(struct process_iterator *it, struct process_filter *filter) { + it->i = 0; + /* Find out how much to allocate for it->pidlist */ + if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0)) <= 0) { + fprintf(stderr, "proc_listpids: %s\n", strerror(errno)); + return -1; + } + /* Allocate and populate it->pidlist */ + if ((it->pidlist = (int *)malloc((it->count)*sizeof(int))) == NULL) { + fprintf(stderr, "malloc: %s\n", strerror(errno)); + } + if ((it->count = proc_listpids(PROC_ALL_PIDS, 0, it->pidlist, it->count)) <= 0) { + fprintf(stderr, "proc_listpids: %s\n", strerror(errno)); + return -1; + } + it->filter = filter; + return 0; +} + +static int pti2proc(struct proc_taskallinfo *ti, struct process *process) { + int bytes; + process->pid = ti->pbsd.pbi_pid; + process->ppid = ti->pbsd.pbi_ppid; + process->starttime = ti->pbsd.pbi_start_tvsec; + process->cputime = ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system; + bytes = strlen(ti->pbsd.pbi_comm); + memcpy(process->command, ti->pbsd.pbi_comm, (bytes < PATH_MAX ? bytes : PATH_MAX) + 1); + return 0; +} + +static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) { + int bytes; + bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(ti)); + if (bytes <= 0) { + fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno)); + return -1; + } else if (bytes < sizeof(ti)) { + fprintf(stderr, "proc_pidinfo: too few bytes; expected %ld, got %d\n", sizeof(ti), bytes); + return -1; + } return 0; } int get_next_process(struct process_iterator *it, struct process *p) { + struct proc_taskallinfo *ti = NULL; + if (it->i == it->count) return -1; + if (it->filter->pid != 0 && !it->filter->include_children) { + if (get_process_pti(it->filter->pid, ti) != 0) { + it->i = it->count = 0; + return -1; + } + it->i = it->count = 1; + return pti2proc(ti, p); + } + while (it->i < it->count) { + get_process_pti(it->pidlist[it->i], ti); + if (ti == NULL || ti->pbsd.pbi_flags & PROC_FLAG_SYSTEM) { + it->i++; + continue; + } + if (it->filter->pid != 0 && it->filter->include_children) { + pti2proc(ti, p); + it->i++; + if (p->pid != it->filter->pid && p->ppid != it->filter->pid) + continue; + return 0; + } + else if (it->filter->pid == 0) + { + pti2proc(ti, p); + it->i++; + return 0; + } + } return -1; } int close_process_iterator(struct process_iterator *it) { + free(it->pidlist); + it->pidlist = NULL; + it->filter = NULL; + it->count = 0; + it->i = 0; return 0; } - - // 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; - -// 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; -// } -- cgit v1.2.3 From fc6b7096adb1a986f94e0be25162ff6182445702 Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 2 Jul 2012 01:49:17 +0200 Subject: Fix erroneous Makefile in tests/ --- tests/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index ffc80fa..764db87 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -12,7 +12,7 @@ endif all:: $(TARGETS) -busy: busy.c $(SYSLIBS) +busy: busy.c $(CC) -o busy busy.c $(SYSLIBS) $(CFLAGS) process_iterator_test: process_iterator_test.c $(LIBS) -- cgit v1.2.3 From ffb330fe224974cd5f5ba7746779d9ad3a030d6a Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 2 Jul 2012 02:01:48 +0200 Subject: Fixed some pointer fails in process_iterator_apple.c --- src/process_iterator_apple.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index 1f98bf2..5a7d35e 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -55,7 +55,7 @@ static int pti2proc(struct proc_taskallinfo *ti, struct process *process) { static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) { int bytes; - bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(ti)); + bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(*ti)); if (bytes <= 0) { fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno)); return -1; @@ -67,24 +67,25 @@ static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) { } int get_next_process(struct process_iterator *it, struct process *p) { - struct proc_taskallinfo *ti = NULL; if (it->i == it->count) return -1; if (it->filter->pid != 0 && !it->filter->include_children) { - if (get_process_pti(it->filter->pid, ti) != 0) { + struct proc_taskallinfo ti; + if (get_process_pti(it->filter->pid, &ti) != 0) { it->i = it->count = 0; return -1; } it->i = it->count = 1; - return pti2proc(ti, p); + return pti2proc(&ti, p); } while (it->i < it->count) { - get_process_pti(it->pidlist[it->i], ti); - if (ti == NULL || ti->pbsd.pbi_flags & PROC_FLAG_SYSTEM) { + struct proc_taskallinfo ti; + get_process_pti(it->pidlist[it->i], &ti); + if (ti.pbsd.pbi_flags & PROC_FLAG_SYSTEM) { it->i++; continue; } if (it->filter->pid != 0 && it->filter->include_children) { - pti2proc(ti, p); + pti2proc(&ti, p); it->i++; if (p->pid != it->filter->pid && p->ppid != it->filter->pid) continue; @@ -92,7 +93,7 @@ int get_next_process(struct process_iterator *it, struct process *p) { } else if (it->filter->pid == 0) { - pti2proc(ti, p); + pti2proc(&ti, p); it->i++; return 0; } -- cgit v1.2.3 From c52cbe61f94b34f421c8ea134ef10bb64b35f365 Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Mon, 2 Jul 2012 02:25:43 +0200 Subject: process->cputime should be millisecons now --- src/process_iterator_apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index 5a7d35e..6baaf5c 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -47,7 +47,7 @@ static int pti2proc(struct proc_taskallinfo *ti, struct process *process) { process->pid = ti->pbsd.pbi_pid; process->ppid = ti->pbsd.pbi_ppid; process->starttime = ti->pbsd.pbi_start_tvsec; - process->cputime = ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system; + process->cputime = (ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system) / 1000; bytes = strlen(ti->pbsd.pbi_comm); memcpy(process->command, ti->pbsd.pbi_comm, (bytes < PATH_MAX ? bytes : PATH_MAX) + 1); return 0; -- cgit v1.2.3 From 9032acb2f9d690c3023357895fee77559e587c1f Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Wed, 4 Jul 2012 13:14:28 +0200 Subject: process->cputime is really milliseconds this time. --- src/process_iterator_apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index 6baaf5c..2270ad6 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -47,7 +47,7 @@ static int pti2proc(struct proc_taskallinfo *ti, struct process *process) { process->pid = ti->pbsd.pbi_pid; process->ppid = ti->pbsd.pbi_ppid; process->starttime = ti->pbsd.pbi_start_tvsec; - process->cputime = (ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system) / 1000; + process->cputime = (ti->ptinfo.pti_total_user + ti->ptinfo.pti_total_system) / 1000000; bytes = strlen(ti->pbsd.pbi_comm); memcpy(process->command, ti->pbsd.pbi_comm, (bytes < PATH_MAX ? bytes : PATH_MAX) + 1); return 0; -- cgit v1.2.3 From 223bbb82c94a9f21afbb79ea3e6eb5800d87b03d Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Wed, 4 Jul 2012 14:10:44 +0200 Subject: Silence EPERM and ESRCH errors in get_process_pti --- src/process_iterator_apple.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index 2270ad6..98af1aa 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -57,7 +57,9 @@ static int get_process_pti(pid_t pid, struct proc_taskallinfo *ti) { int bytes; bytes = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, ti, sizeof(*ti)); if (bytes <= 0) { - fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno)); + if (!(errno & (EPERM | ESRCH))) { + fprintf(stderr, "proc_pidinfo: %s\n", strerror(errno)); + } return -1; } else if (bytes < sizeof(ti)) { fprintf(stderr, "proc_pidinfo: too few bytes; expected %ld, got %d\n", sizeof(ti), bytes); -- cgit v1.2.3 From b60ce48914d78cd827c88f29c863e3527ecff1f2 Mon Sep 17 00:00:00 2001 From: Simon Sigurdhsson Date: Wed, 4 Jul 2012 16:28:32 +0200 Subject: Fixed errors, OSX build now passes all tests. --- src/process_iterator_apple.c | 33 ++++++++++++++++++++++++++++++++- tests/process_iterator_test.c | 10 ++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/process_iterator_apple.c b/src/process_iterator_apple.c index 98af1aa..b6cd468 100644 --- a/src/process_iterator_apple.c +++ b/src/process_iterator_apple.c @@ -23,6 +23,31 @@ #include #include +int unique_nonzero_ints(int* arr_in, int len_in, int* arr_out) { + int* source = arr_in; + if (arr_out == NULL) return -1; + if (arr_in == arr_out) { + source = malloc(sizeof(int)*len_in); + memcpy(source, arr_in, sizeof(int)*len_in); + memset(arr_out, -1, sizeof(int)*len_in); + } + int len_out = 0; + for (int i=0; ii = 0; /* Find out how much to allocate for it->pidlist */ @@ -38,6 +63,7 @@ int init_process_iterator(struct process_iterator *it, struct process_filter *fi fprintf(stderr, "proc_listpids: %s\n", strerror(errno)); return -1; } + it->count = unique_nonzero_ints(it->pidlist, it->count, it->pidlist); it->filter = filter; return 0; } @@ -81,7 +107,10 @@ int get_next_process(struct process_iterator *it, struct process *p) { } while (it->i < it->count) { struct proc_taskallinfo ti; - get_process_pti(it->pidlist[it->i], &ti); + if (get_process_pti(it->pidlist[it->i], &ti) != 0) { + it->i++; + continue; + } if (ti.pbsd.pbi_flags & PROC_FLAG_SYSTEM) { it->i++; continue; @@ -89,6 +118,8 @@ int get_next_process(struct process_iterator *it, struct process *p) { if (it->filter->pid != 0 && it->filter->include_children) { pti2proc(&ti, p); it->i++; + if (p->pid != it->pidlist[it->i - 1]) // I don't know why this can happen + continue; if (p->pid != it->filter->pid && p->ppid != it->filter->pid) continue; return 0; diff --git a/tests/process_iterator_test.c b/tests/process_iterator_test.c index 3d5e885..20ef479 100644 --- a/tests/process_iterator_test.c +++ b/tests/process_iterator_test.c @@ -28,6 +28,10 @@ #include #include +#ifdef __APPLE__ +#include +#endif + #include #include @@ -198,7 +202,13 @@ void test_process_name(const char * command) assert(get_next_process(&it, &process) == 0); assert(process.pid == getpid()); assert(process.ppid == getppid()); + #ifdef __APPLE__ + // proc_pidinfo only gives us the first 15 chars + // of the basename of the command on OSX. + assert(strncmp(basename((char*)command), process.command, 15) == 0); + #else assert(strncmp(command, process.command, strlen(process.command)) == 0); + #endif assert(get_next_process(&it, &process) != 0); close_process_iterator(&it); } -- cgit v1.2.3