summaryrefslogtreecommitdiffstats
path: root/darwin
diff options
context:
space:
mode:
authorDavid Hunt <dhunt@iolanthe.attlocal.net>2015-07-13 01:17:14 -0500
committerHisham Muhammad <hisham@gobolinux.org>2015-08-19 13:51:49 -0300
commit43ef703f034be4e347ab94250101cd8f23409952 (patch)
tree157b1c2180b056ef0c1d45bf80c47b3808175689 /darwin
parent70e7c8db592408f45b958238d4bbf0048886f6fc (diff)
Start supporting actual data
Diffstat (limited to 'darwin')
-rw-r--r--darwin/DarwinCRT.c1
-rw-r--r--darwin/DarwinProcess.c286
-rw-r--r--darwin/DarwinProcess.h16
-rw-r--r--darwin/DarwinProcessList.c140
-rw-r--r--darwin/DarwinProcessList.h18
-rw-r--r--darwin/Platform.c25
-rw-r--r--darwin/Platform.h2
7 files changed, 433 insertions, 55 deletions
diff --git a/darwin/DarwinCRT.c b/darwin/DarwinCRT.c
index 49f98cdc..e998f000 100644
--- a/darwin/DarwinCRT.c
+++ b/darwin/DarwinCRT.c
@@ -9,6 +9,7 @@ in the source distribution for its full text.
#include "CRT.h"
#include <stdio.h>
#include <stdlib.h>
+#include <execinfo.h>
void CRT_handleSIGSEGV(int sgn) {
(void) sgn;
diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c
index 7054cf46..64388490 100644
--- a/darwin/DarwinProcess.c
+++ b/darwin/DarwinProcess.c
@@ -7,12 +7,14 @@ in the source distribution for its full text.
#include "Process.h"
#include "DarwinProcess.h"
+
#include <stdlib.h>
+#include <libproc.h>
+#include <string.h>
/*{
#include "Settings.h"
-
-#define Process_delete UnsupportedProcess_delete
+#include <sys/sysctl.h>
}*/
@@ -23,7 +25,7 @@ Process* DarwinProcess_new(Settings* settings) {
return this;
}
-void DarwinProcess_delete(Object* cast) {
+void Process_delete(Object* cast) {
Process* this = (Process*) cast;
Object_setClass(this, Class(Process));
Process_done((Process*)cast);
@@ -31,3 +33,281 @@ void DarwinProcess_delete(Object* cast) {
free(this);
}
+bool Process_isThread(Process* this) {
+ return false;
+}
+
+void DarwinProcess_setStartTime(Process *proc, struct extern_proc *ep, time_t now) {
+ struct tm date;
+
+ proc->starttime_ctime = ep->p_starttime.tv_sec;
+ (void) localtime_r(&proc->starttime_ctime, &date);
+ strftime(proc->starttime_show, 7, ((proc->starttime_ctime > now - 86400) ? "%R " : "%b%d "), &date);
+}
+
+char *DarwinProcessList_getCmdLine(struct kinfo_proc* k, int show_args ) {
+ /* This function is from the old Mac version of htop. Originally from ps? */
+ int mib[3], argmax, nargs, c = 0;
+ size_t size;
+ char *procargs, *sp, *np, *cp, *retval;
+
+ /* Get the maximum process arguments size. */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ size = sizeof( argmax );
+ if ( sysctl( mib, 2, &argmax, &size, NULL, 0 ) == -1 ) {
+ goto ERROR_A;
+ }
+
+ /* Allocate space for the arguments. */
+ procargs = ( char * ) malloc( argmax );
+ if ( procargs == NULL ) {
+ goto ERROR_A;
+ }
+
+ /*
+ * Make a sysctl() call to get the raw argument space of the process.
+ * The layout is documented in start.s, which is part of the Csu
+ * project. In summary, it looks like:
+ *
+ * /---------------\ 0x00000000
+ * : :
+ * : :
+ * |---------------|
+ * | argc |
+ * |---------------|
+ * | arg[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | arg[argc - 1] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | env[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | env[n] |
+ * |---------------|
+ * | 0 |
+ * |---------------| <-- Beginning of data returned by sysctl() is here.
+ * | argc |
+ * |---------------|
+ * | exec_path |
+ * |:::::::::::::::|
+ * | |
+ * | String area. |
+ * | |
+ * |---------------| <-- Top of stack.
+ * : :
+ * : :
+ * \---------------/ 0xffffffff
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = k->kp_proc.p_pid;
+
+ size = ( size_t ) argmax;
+ if ( sysctl( mib, 3, procargs, &size, NULL, 0 ) == -1 ) {
+ goto ERROR_B;
+ }
+
+ memcpy( &nargs, procargs, sizeof( nargs ) );
+ cp = procargs + sizeof( nargs );
+
+ /* Skip the saved exec_path. */
+ for ( ; cp < &procargs[size]; cp++ ) {
+ if ( *cp == '\0' ) {
+ /* End of exec_path reached. */
+ break;
+ }
+ }
+ if ( cp == &procargs[size] ) {
+ goto ERROR_B;
+ }
+
+ /* Skip trailing '\0' characters. */
+ for ( ; cp < &procargs[size]; cp++ ) {
+ if ( *cp != '\0' ) {
+ /* Beginning of first argument reached. */
+ break;
+ }
+ }
+ if ( cp == &procargs[size] ) {
+ goto ERROR_B;
+ }
+ /* Save where the argv[0] string starts. */
+ sp = cp;
+
+ /*
+ * Iterate through the '\0'-terminated strings and convert '\0' to ' '
+ * until a string is found that has a '=' character in it (or there are
+ * no more strings in procargs). There is no way to deterministically
+ * know where the command arguments end and the environment strings
+ * start, which is why the '=' character is searched for as a heuristic.
+ */
+ for ( np = NULL; c < nargs && cp < &procargs[size]; cp++ ) {
+ if ( *cp == '\0' ) {
+ c++;
+ if ( np != NULL ) {
+ /* Convert previous '\0'. */
+ *np = ' ';
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+
+ if ( !show_args ) {
+ /*
+ * Don't convert '\0' characters to ' '.
+ * However, we needed to know that the
+ * command name was terminated, which we
+ * now know.
+ */
+ break;
+ }
+ }
+ }
+#if 0
+ /*
+ * If eflg is non-zero, continue converting '\0' characters to ' '
+ * characters until no more strings that look like environment settings
+ * follow.
+ */
+ if ( ( eflg != 0 )
+ && ( ( getuid( ) == 0 )
+ || ( k->kp_eproc.e_pcred.p_ruid == getuid( ) ) ) ) {
+ for ( ; cp < &procargs[size]; cp++ ) {
+ if ( *cp == '\0' ) {
+ if ( np != NULL ) {
+ if ( &np[1] == cp ) {
+ /*
+ * Two '\0' characters in a row.
+ * This should normally only
+ * happen after all the strings
+ * have been seen, but in any
+ * case, stop parsing.
+ */
+ break;
+ }
+ /* Convert previous '\0'. */
+ *np = ' ';
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+ }
+ }
+ }
+#endif
+
+ /*
+ * sp points to the beginning of the arguments/environment string, and
+ * np should point to the '\0' terminator for the string.
+ */
+ if ( np == NULL || np == sp ) {
+ /* Empty or unterminated string. */
+ goto ERROR_B;
+ }
+
+ /* Make a copy of the string. */
+ retval = strdup(sp);
+
+ /* Clean up. */
+ free( procargs );
+
+ return retval;
+
+ERROR_B:
+ free( procargs );
+ERROR_A:
+ retval = strdup(k->kp_proc.p_comm);
+
+ return retval;
+}
+
+void DarwinProcess_setFromKInfoProc(Process *proc, struct kinfo_proc *ps, time_t now, bool exists) {
+ struct extern_proc *ep = &ps->kp_proc;
+
+ /* UNSET HERE :
+ *
+ * processor
+ * user (set at ProcessList level)
+ * nlwp
+ * percent_cpu
+ * percent_mem
+ * m_size
+ * m_resident
+ * minflt
+ * majflt
+ */
+
+ /* First, the "immutable" parts */
+ if(!exists) {
+ /* Set the PID/PGID/etc. */
+ proc->pid = ep->p_pid;
+ proc->ppid = ps->kp_eproc.e_ppid;
+ proc->pgrp = ps->kp_eproc.e_pgid;
+ proc->session = 0; /* TODO Get the session id */
+ proc->tgid = ps->kp_eproc.e_tpgid;
+ proc->st_uid = ps->kp_eproc.e_ucred.cr_uid;
+ /* e_tdev = (major << 24) | (minor & 0xffffff) */
+ /* e_tdev == -1 for "no device" */
+ proc->tty_nr = ps->kp_eproc.e_tdev & 0xff; /* TODO tty_nr is unsigned */
+
+ DarwinProcess_setStartTime(proc, ep, now);
+
+ /* The command is from the old Mac htop */
+ char *slash;
+
+ proc->comm = DarwinProcessList_getCmdLine(ps, false);
+ slash = strrchr(proc->comm, '/');
+ proc->basenameOffset = (NULL != slash) ? (slash - proc->comm) : 0;
+ }
+
+ /* Mutable information */
+ proc->nice = ep->p_nice;
+ proc->priority = ep->p_priority;
+
+ /* Set the state */
+ switch(ep->p_stat) {
+ case SIDL: proc->state = 'I'; break;
+ case SRUN: proc->state = 'R'; break;
+ case SSLEEP: proc->state = 'S'; break;
+ case SSTOP: proc->state = 'T'; break;
+ case SZOMB: proc->state = 'Z'; break;
+ default: proc->state = '?'; break;
+ }
+
+ /* Make sure the updated flag is set */
+ proc->updated = true;
+}
+
+void DarwinProcess_setFromLibprocPidinfo(Process *proc, uint64_t total_memory, bool preExisting) {
+ struct proc_taskinfo pti;
+
+ if(sizeof(pti) == proc_pidinfo(proc->pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) {
+ proc->nlwp = pti.pti_threadnum;
+ proc->m_size = pti.pti_virtual_size / 1024;
+ proc->m_resident = pti.pti_resident_size / 1024;
+ proc->majflt = pti.pti_faults;
+ proc->percent_mem = (double)pti.pti_resident_size * 100.0 / (double)total_memory;
+ }
+}
+
+void DarwinProcess_parseThreads(Process *proc, time_t now, bool preExisting) {
+ static const size_t IDS_SZ = sizeof(uint64_t) * 2048;
+
+ uint64_t *thread_ids = (uint64_t *)malloc(IDS_SZ);
+ size_t bytes = proc_pidinfo(proc->pid, PROC_PIDLISTTHREADS, 0, thread_ids, IDS_SZ);
+
+ if(0 < bytes) {
+ size_t count = bytes / sizeof(uint64_t);
+
+ proc->nlwp = count;
+ }
+
+ free(thread_ids); /* TODO Keep reusing this block */
+}
diff --git a/darwin/DarwinProcess.h b/darwin/DarwinProcess.h
index 201650d5..65fff6b7 100644
--- a/darwin/DarwinProcess.h
+++ b/darwin/DarwinProcess.h
@@ -10,13 +10,23 @@ in the source distribution for its full text.
*/
#include "Settings.h"
-
-#define Process_delete DarwinProcess_delete
+#include <sys/sysctl.h>
Process* DarwinProcess_new(Settings* settings);
-void DarwinProcess_delete(Object* cast);
+void Process_delete(Object* cast);
+
+bool Process_isThread(Process* this);
+
+void DarwinProcess_setStartTime(Process *proc, struct extern_proc *ep, time_t now);
+
+char *DarwinProcessList_getCmdLine(struct kinfo_proc* k, int show_args );
+
+void DarwinProcess_setFromKInfoProc(Process *proc, struct kinfo_proc *ps, time_t now, bool exists);
+
+void DarwinProcess_setFromLibprocPidinfo(Process *proc, uint64_t total_memory, bool preExisting);
+void DarwinProcess_parseThreads(Process *proc, time_t now, bool preExisting);
#endif
diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c
index 3fb36365..6187d346 100644
--- a/darwin/DarwinProcessList.c
+++ b/darwin/DarwinProcessList.c
@@ -11,16 +11,85 @@ in the source distribution for its full text.
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <libproc.h>
/*{
+#include <mach/mach_host.h>
+#include <sys/sysctl.h>
+
+typedef struct DarwinProcessList_ {
+ ProcessList super;
+
+ host_basic_info_data_t prev_hinfo;
+ processor_info_data_t prev_cpus;
+} DarwinProcessList;
}*/
+void ProcessList_getHostInfo(host_basic_info_data_t *p) {
+ mach_msg_type_number_t info_size = HOST_BASIC_INFO_COUNT;
+
+ if(0 != host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)p, &info_size)) {
+ fprintf(stderr, "Unable to retrieve host info\n");
+ exit(2);
+ }
+}
+
+unsigned ProcessList_getCPUInfo(processor_info_data_t *p) {
+ mach_msg_type_number_t info_size = PROCESSOR_CPU_LOAD_INFO_COUNT;
+ unsigned cpu_count;
+
+ if(0 != host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &cpu_count, (processor_info_array_t *)p, &info_size)) {
+ fprintf(stderr, "Unable to retrieve CPU info\n");
+ exit(4);
+ }
+
+ return cpu_count;
+}
+
+struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count) {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+ struct kinfo_proc *processes = NULL;
+
+ /* Note the two calls to sysctl(). One to get length and one to get the
+ * data. This -does- mean that the second call could end up with a missing
+ * process entry or two.
+ */
+ *count = 0;
+ if(0 > sysctl(mib, 4, NULL, count, NULL, 0)) {
+ fprintf(stderr, "Unable to get size of kproc_infos");
+ exit(5);
+ }
+
+ processes = (struct kinfo_proc *)malloc(*count);
+ if(NULL == processes) {
+ fprintf(stderr, "Out of memory for kproc_infos\n");
+ exit(6);
+ }
+
+ if(0 > sysctl(mib, 4, processes, count, NULL, 0)) {
+ fprintf(stderr, "Unable to get kinfo_procs\n");
+ exit(7);
+ }
+
+ *count = *count / sizeof(struct kinfo_proc);
+
+ return processes;
+}
+
+
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
- ProcessList* this = calloc(1, sizeof(ProcessList));
- ProcessList_init(this, Class(Process), usersTable, pidWhiteList, userId);
+ DarwinProcessList* this = calloc(1, sizeof(DarwinProcessList));
+
+ ProcessList_init(&this->super, Class(Process), usersTable, pidWhiteList, userId);
- return this;
+ /* Initialize the previous information */
+ this->super.cpuCount = ProcessList_getCPUInfo(&this->prev_cpus);
+ ProcessList_getHostInfo(&this->prev_hinfo);
+
+ return &this->super;
}
void ProcessList_delete(ProcessList* this) {
@@ -29,43 +98,36 @@ void ProcessList_delete(ProcessList* this) {
}
void ProcessList_goThroughEntries(ProcessList* super) {
+ DarwinProcessList *dpl = (DarwinProcessList *)super;
bool preExisting = true;
+ struct kinfo_proc *ps;
+ size_t count;
Process *proc;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL); /* Start processing time */
+
+ /* We use kinfo_procs for initial data since :
+ *
+ * 1) They always succeed.
+ * 2) The contain the basic information.
+ *
+ * We attempt to fill-in additional information with libproc.
+ */
+ ps = ProcessList_getKInfoProcs(&count);
+
+ for(size_t i = 0; i < count; ++i) {
+ proc = ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);
+
+ DarwinProcess_setFromKInfoProc(proc, ps + i, tv.tv_sec, preExisting);
+ DarwinProcess_setFromLibprocPidinfo(proc, dpl->prev_hinfo.max_mem, preExisting);
+
+ if(!preExisting) {
+ proc->user = UsersTable_getRef(super->usersTable, proc->st_uid);
+
+ ProcessList_add(super, proc);
+ }
+ }
- proc = ProcessList_getProcess(super, 1, &preExisting, DarwinProcess_new);
-
- /* Empty values */
- proc->time = proc->time + 10;
- proc->pid = 1;
- proc->ppid = 1;
- proc->tgid = 0;
- proc->comm = "<unsupported architecture>";
- proc->basenameOffset = 0;
- proc->updated = true;
-
- proc->state = 'R';
- proc->show = true; /* Reflected in proc->settings-> "hideXXX" really */
- proc->pgrp = 0;
- proc->session = 0;
- proc->tty_nr = 0;
- proc->tpgid = 0;
- proc->st_uid = 0;
- proc->flags = 0;
- proc->processor = 0;
-
- proc->percent_cpu = 2.5;
- proc->percent_mem = 2.5;
- proc->user = "nobody";
-
- proc->priority = 0;
- proc->nice = 0;
- proc->nlwp = 1;
- strncpy(proc->starttime_show, "Jun 01 ", sizeof(proc->starttime_show));
- proc->starttime_ctime = 1433116800; // Jun 01, 2015
-
- proc->m_size = 100;
- proc->m_resident = 100;
-
- proc->minflt = 20;
- proc->majflt = 20;
+ free(ps);
}
diff --git a/darwin/DarwinProcessList.h b/darwin/DarwinProcessList.h
index ccdf718f..6a4bb094 100644
--- a/darwin/DarwinProcessList.h
+++ b/darwin/DarwinProcessList.h
@@ -9,7 +9,25 @@ Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
+#include <mach/mach_host.h>
+#include <sys/sysctl.h>
+typedef struct DarwinProcessList_ {
+ ProcessList super;
+
+ host_basic_info_data_t prev_hinfo;
+ vm_statistics64_data_t prev_vminfo;
+ processor_info_data_t prev_cpus;
+} DarwinProcessList;
+
+
+void ProcessList_getHostInfo(host_basic_info_data_t *p);
+
+void ProcessList_getVMInfo(vm_statistics64_data_t *p);
+
+unsigned ProcessList_getCPUInfo(processor_info_data_t *p);
+
+struct kinfo_proc *ProcessList_getKInfoProcs(size_t *count);
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
diff --git a/darwin/Platform.c b/darwin/Platform.c
index 99e90801..a1a3471e 100644
--- a/darwin/Platform.c
+++ b/darwin/Platform.c
@@ -16,6 +16,8 @@ in the source distribution for its full text.
#include "HostnameMeter.h"
#include "UptimeMeter.h"
+#include <stdlib.h>
+
/*{
#include "Action.h"
#include "BatteryMeter.h"
@@ -87,13 +89,22 @@ int Platform_getUptime() {
}
void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
- *one = 0;
- *five = 0;
- *fifteen = 0;
+ double results[3];
+
+ if(3 == getloadavg(results, 3)) {
+ *one = results[0];
+ *five = results[1];
+ *fifteen = results[2];
+ } else {
+ *one = 0;
+ *five = 0;
+ *fifteen = 0;
+ }
}
int Platform_getMaxPid() {
- return 1;
+ /* http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/proc_internal.hh */
+ return 99999;
}
void Process_setupColumnWidths() {
@@ -121,6 +132,8 @@ void Process_setupColumnWidths() {
}
double Platform_setCPUValues(Meter* this, int cpu) {
+ DarwinProcessList *dpl = (DarwinProcessList *)this->pl;
+
return 0.0;
}
@@ -130,7 +143,3 @@ void Platform_setMemoryValues(Meter* this) {
void Platform_setSwapValues(Meter* this) {
}
-bool Process_isThread(Process* this) {
- return false;
-}
-
diff --git a/darwin/Platform.h b/darwin/Platform.h
index 4fc06f71..7da13321 100644
--- a/darwin/Platform.h
+++ b/darwin/Platform.h
@@ -40,7 +40,5 @@ void Platform_setMemoryValues(Meter* this);
void Platform_setSwapValues(Meter* this);
-bool Process_isThread(Process* this);
-
#endif

© 2014-2024 Faster IT GmbH | imprint | privacy policy