mirror of https://github.com/xzeldon/htop.git
Start supporting actual data
This commit is contained in:
parent
70e7c8db59
commit
43ef703f03
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
proc = ProcessList_getProcess(super, 1, &preExisting, DarwinProcess_new);
|
||||
gettimeofday(&tv, NULL); /* Start processing time */
|
||||
|
||||
/* 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;
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
proc = ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);
|
||||
|
||||
proc->percent_cpu = 2.5;
|
||||
proc->percent_mem = 2.5;
|
||||
proc->user = "nobody";
|
||||
DarwinProcess_setFromKInfoProc(proc, ps + i, tv.tv_sec, preExisting);
|
||||
DarwinProcess_setFromLibprocPidinfo(proc, dpl->prev_hinfo.max_mem, preExisting);
|
||||
|
||||
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
|
||||
if(!preExisting) {
|
||||
proc->user = UsersTable_getRef(super->usersTable, proc->st_uid);
|
||||
|
||||
proc->m_size = 100;
|
||||
proc->m_resident = 100;
|
||||
ProcessList_add(super, proc);
|
||||
}
|
||||
}
|
||||
|
||||
proc->minflt = 20;
|
||||
proc->majflt = 20;
|
||||
free(ps);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,5 @@ void Platform_setMemoryValues(Meter* this);
|
|||
|
||||
void Platform_setSwapValues(Meter* this);
|
||||
|
||||
bool Process_isThread(Process* this);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue