diff options
-rw-r--r-- | Action.c | 11 | ||||
-rw-r--r-- | Affinity.c | 19 | ||||
-rw-r--r-- | Affinity.h | 9 | ||||
-rw-r--r-- | CRT.c | 8 | ||||
-rw-r--r-- | CRT.h | 2 | ||||
-rw-r--r-- | InfoScreen.c | 1 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | MetersPanel.c | 5 | ||||
-rw-r--r-- | Panel.c | 2 | ||||
-rw-r--r-- | Process.c | 5 | ||||
-rw-r--r-- | ProcessList.c | 10 | ||||
-rw-r--r-- | ProcessList.h | 4 | ||||
-rw-r--r-- | ScreenManager.c | 28 | ||||
-rwxr-xr-x | autogen.sh | 14 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | darwin/DarwinProcess.c | 146 | ||||
-rw-r--r-- | darwin/DarwinProcess.h | 9 | ||||
-rw-r--r-- | darwin/DarwinProcessList.c | 4 | ||||
-rw-r--r-- | freebsd/FreeBSDProcess.c | 4 | ||||
-rw-r--r-- | freebsd/FreeBSDProcessList.c | 25 | ||||
-rw-r--r-- | freebsd/FreeBSDProcessList.h | 1 | ||||
-rw-r--r-- | freebsd/Platform.c | 11 | ||||
-rw-r--r-- | htop.c | 196 | ||||
-rw-r--r-- | linux/LinuxProcess.c | 16 | ||||
-rw-r--r-- | linux/LinuxProcessList.c | 53 | ||||
-rw-r--r-- | openbsd/OpenBSDProcessList.c | 104 | ||||
-rw-r--r-- | openbsd/OpenBSDProcessList.h | 14 | ||||
-rwxr-xr-x | test_spec.lua | 146 | ||||
-rw-r--r-- | unsupported/Platform.c | 44 | ||||
-rw-r--r-- | unsupported/Platform.h | 12 |
30 files changed, 393 insertions, 524 deletions
@@ -271,7 +271,7 @@ static Htop_Reaction actionQuit() { static Htop_Reaction actionSetAffinity(State* st) { if (st->pl->cpuCount == 1) return HTOP_OK; -#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) +#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY) Panel* panel = st->panel; Process* p = (Process*) Panel_getSelected(panel); @@ -387,6 +387,7 @@ static struct { const char* key; const char* info; } helpLeft[] = { { .key = " F3 /: ", .info = "incremental name search" }, { .key = " F4 \\: ",.info = "incremental name filtering" }, { .key = " F5 t: ", .info = "tree view" }, + { .key = " p: ", .info = "toggle program path" }, { .key = " u: ", .info = "show processes of a single user" }, { .key = " H: ", .info = "hide/show user process threads" }, { .key = " K: ", .info = "hide/show kernel threads" }, @@ -405,11 +406,11 @@ static struct { const char* key; const char* info; } helpRight[] = { { .key = " F9 k: ", .info = "kill process/tagged processes" }, { .key = " F7 ]: ", .info = "higher priority (root only)" }, { .key = " F8 [: ", .info = "lower priority (+ nice)" }, -#if (HAVE_LIBHWLOC || HAVE_NATIVE_AFFINITY) +#if (HAVE_LIBHWLOC || HAVE_LINUX_AFFINITY) { .key = " a: ", .info = "set CPU affinity" }, #endif { .key = " e: ", .info = "show process environment" }, - { .key = " i: ", .info = "set IO prority" }, + { .key = " i: ", .info = "set IO priority" }, { .key = " l: ", .info = "list open files with lsof" }, { .key = " s: ", .info = "trace syscalls with strace" }, { .key = " ", .info = "" }, @@ -479,8 +480,8 @@ static Htop_Reaction actionHelp(State* st) { for (int i = 0; helpLeft[i].key; i++) { mvaddstr(9+i, 0, helpLeft[i].key); } for (int i = 0; helpRight[i].key; i++) { mvaddstr(9+i, 40, helpRight[i].key); } attrset(CRT_colors[PROCESS_THREAD]); - mvaddstr(15, 32, "threads"); - mvaddstr(16, 26, "threads"); + mvaddstr(16, 32, "threads"); + mvaddstr(17, 26, "threads"); attrset(CRT_colors[DEFAULT_COLOR]); attrset(CRT_colors[HELP_BOLD]); @@ -10,8 +10,13 @@ in the source distribution for its full text. #include <stdlib.h> #ifdef HAVE_LIBHWLOC -#include <hwloc/linux.h> -#elif HAVE_NATIVE_AFFINITY +#include <hwloc.h> +#if __linux__ +#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD +#else +#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS +#endif +#elif HAVE_LINUX_AFFINITY #include <sched.h> #endif @@ -55,7 +60,7 @@ void Affinity_add(Affinity* this, int id) { Affinity* Affinity_get(Process* proc, ProcessList* pl) { hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); - bool ok = (hwloc_linux_get_tid_cpubind(pl->topology, proc->pid, cpuset) == 0); + bool ok = (hwloc_get_proc_cpubind(pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); Affinity* affinity = NULL; if (ok) { affinity = Affinity_new(pl); @@ -76,15 +81,15 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl) { bool Affinity_set(Process* proc, Affinity* this) { hwloc_cpuset_t cpuset = hwloc_bitmap_alloc(); - for (int i = 0; i < affinity->used; i++) { - hwloc_bitmap_set(cpuset, affinity->cpus[i]); + for (int i = 0; i < this->used; i++) { + hwloc_bitmap_set(cpuset, this->cpus[i]); } - bool ok = (hwloc_linux_set_tid_cpubind(this->pl->topology, proc->pid, cpuset) == 0); + bool ok = (hwloc_set_proc_cpubind(this->pl->topology, proc->pid, cpuset, HTOP_HWLOC_CPUBIND_FLAG) == 0); hwloc_bitmap_free(cpuset); return ok; } -#elif HAVE_NATIVE_AFFINITY +#elif HAVE_LINUX_AFFINITY Affinity* Affinity_get(Process* proc, ProcessList* pl) { cpu_set_t cpuset; @@ -10,7 +10,12 @@ in the source distribution for its full text. */ #ifdef HAVE_LIBHWLOC -#elif HAVE_NATIVE_AFFINITY +#if __linux__ +#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_THREAD +#else +#define HTOP_HWLOC_CPUBIND_FLAG HWLOC_CPUBIND_PROCESS +#endif +#elif HAVE_LINUX_AFFINITY #endif #include "Process.h" @@ -36,7 +41,7 @@ Affinity* Affinity_get(Process* proc, ProcessList* pl); bool Affinity_set(Process* proc, Affinity* this); -#elif HAVE_NATIVE_AFFINITY +#elif HAVE_LINUX_AFFINITY Affinity* Affinity_get(Process* proc, ProcessList* pl); @@ -125,6 +125,8 @@ void CRT_fatalError(const char* note) __attribute__ ((noreturn)); void CRT_handleSIGSEGV(int sgn); +#define KEY_ALT(x) KEY_F(60) + (x - 'A') + }*/ const char *CRT_treeStrAscii[TREE_STR_COUNT] = { @@ -587,6 +589,11 @@ void CRT_init(int delay, int colorScheme) { define_key("\033[13~", KEY_F(3)); define_key("\033[14~", KEY_F(4)); define_key("\033[17;2~", KEY_F(18)); + char sequence[3] = "\033a"; + for (char c = 'a'; c <= 'z'; c++) { + sequence[1] = c; + define_key(sequence, KEY_ALT('A' + (c - 'a'))); + } } #ifndef DEBUG signal(11, CRT_handleSIGSEGV); @@ -618,6 +625,7 @@ void CRT_init(int delay, int colorScheme) { #else mousemask(BUTTON1_RELEASED, NULL); #endif + } void CRT_done() { @@ -115,6 +115,8 @@ void CRT_fatalError(const char* note) __attribute__ ((noreturn)); void CRT_handleSIGSEGV(int sgn); +#define KEY_ALT(x) KEY_F(60) + (x - 'A') + extern const char *CRT_treeStrAscii[TREE_STR_COUNT]; diff --git a/InfoScreen.c b/InfoScreen.c index 7ce9ca6a..a6dd55ad 100644 --- a/InfoScreen.c +++ b/InfoScreen.c @@ -116,6 +116,7 @@ void InfoScreen_run(InfoScreen* this) { if (this->inc->active) move(LINES-1, CRT_cursorX); + ESCDELAY = 25; int ch = getch(); if (ch == ERR) { diff --git a/Makefile.am b/Makefile.am index 8b316270..19c9eb47 100644 --- a/Makefile.am +++ b/Makefile.am @@ -95,7 +95,7 @@ debug: $(MAKE) all CFLAGS="" AM_CPPFLAGS="-ggdb -DDEBUG" coverage: - $(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" AM_LDFLAGS="-lgcov" + $(MAKE) all CFLAGS="" AM_CPPFLAGS="-fprofile-arcs -ftest-coverage -DDEBUG" LDFLAGS="-lgcov" .c.h: @srcdir@/scripts/MakeHeader.py $< diff --git a/MetersPanel.c b/MetersPanel.c index bdbe83ee..302b6d1a 100644 --- a/MetersPanel.c +++ b/MetersPanel.c @@ -50,7 +50,10 @@ static void MetersPanel_delete(Object* object) { void MetersPanel_setMoving(MetersPanel* this, bool moving) { Panel* super = (Panel*) this; this->moving = moving; - ((ListItem*)Panel_getSelected(super))->moving = moving; + ListItem* selected = (ListItem*)Panel_getSelected(super); + if (selected) { + selected->moving = moving; + } if (!moving) { Panel_setSelectionColor(super, CRT_colors[PANEL_SELECTION_FOCUS]); Panel_setDefaultBar(super); @@ -441,7 +441,7 @@ bool Panel_onKey(Panel* this, int key) { } // ensure selection within bounds - if (this->selected < 0) { + if (this->selected < 0 || size == 0) { this->selected = 0; this->needsRedraw = true; } else if (this->selected >= size) { @@ -335,7 +335,10 @@ void Process_outputRate(RichString* str, char* buffer, int n, double rate, int c largeNumberColor = CRT_colors[PROCESS]; processMegabytesColor = CRT_colors[PROCESS]; } - if (rate < ONE_K) { + if (rate == -1) { + int len = snprintf(buffer, n, " no perm "); + RichString_appendn(str, CRT_colors[PROCESS_SHADOW], buffer, len); + } else if (rate < ONE_K) { int len = snprintf(buffer, n, "%7.2f B/s ", rate); RichString_appendn(str, processColor, buffer, len); } else if (rate < ONE_K * ONE_K) { diff --git a/ProcessList.c b/ProcessList.c index 5f5151f6..a49b4f12 100644 --- a/ProcessList.c +++ b/ProcessList.c @@ -22,6 +22,10 @@ in the source distribution for its full text. #include "Process.h" #include "Settings.h" +#ifdef HAVE_LIBHWLOC +#include <hwloc.h> +#endif + #ifndef MAX_NAME #define MAX_NAME 128 #endif @@ -104,6 +108,11 @@ ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* } void ProcessList_done(ProcessList* this) { +#ifdef HAVE_LIBHWLOC + if (this->topologyOk) { + hwloc_topology_destroy(this->topology); + } +#endif Hashtable_delete(this->processTable); Vector_delete(this->processes); Vector_delete(this->processes2); @@ -307,6 +316,7 @@ void ProcessList_scan(ProcessList* this) { for (int i = 0; i < Vector_size(this->processes); i++) { Process* p = (Process*) Vector_get(this->processes, i); p->updated = false; + p->show = true; } this->totalTasks = 0; diff --git a/ProcessList.h b/ProcessList.h index f96481ea..572d4843 100644 --- a/ProcessList.h +++ b/ProcessList.h @@ -16,6 +16,10 @@ in the source distribution for its full text. #include "Process.h" #include "Settings.h" +#ifdef HAVE_LIBHWLOC +#include <hwloc.h> +#endif + #ifndef MAX_NAME #define MAX_NAME 128 #endif diff --git a/ScreenManager.c b/ScreenManager.c index a33d3420..db3fdee4 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -189,6 +189,7 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { } int prevCh = ch; + ESCDELAY = 25; ch = getch(); HandlerResult result = IGNORED; @@ -244,28 +245,11 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { redraw = false; continue; } - else if (ch == 27) { - int ch2 = getch(); - if (ch2 != ERR) { - switch(ch2) - { - case 'h': - ch = KEY_LEFT; - break; - case 'j': - ch = KEY_DOWN; - break; - case 'k': - ch = KEY_UP; - break; - case 'l': - ch = KEY_RIGHT; - break; - default: - ungetch(ch2); - break; - } - } + switch (ch) { + case KEY_ALT('H'): ch = KEY_LEFT; break; + case KEY_ALT('J'): ch = KEY_DOWN; break; + case KEY_ALT('K'): ch = KEY_UP; break; + case KEY_ALT('L'): ch = KEY_RIGHT; break; } redraw = true; if (Panel_eventHandlerFn(panelFocus)) { @@ -1,15 +1,3 @@ #!/bin/sh - -glibtoolize=$(which glibtoolize 2> /dev/null) -if [ ${#glibtoolize} -gt 0 ] -then libtoolize=glibtoolize -else libtoolize=libtoolize -fi - mkdir -p m4 -aclocal -I m4 -autoconf -autoheader -$libtoolize --copy --force -automake --add-missing --copy - +autoreconf --install --force diff --git a/configure.ac b/configure.ac index 3bd58bce..6073175f 100644 --- a/configure.ac +++ b/configure.ac @@ -211,8 +211,8 @@ if test "$my_htop_platform" = "openbsd"; then AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"]) fi -AC_ARG_ENABLE(native_affinity, [AC_HELP_STRING([--enable-native-affinity], [enable native sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_native_affinity="yes") -if test "x$enable_native_affinity" = xyes -a "x$cross_compiling" = xno; then +AC_ARG_ENABLE(linux_affinity, [AC_HELP_STRING([--enable-linux-affinity], [enable Linux sched_setaffinity and sched_getaffinity for affinity support, disables hwloc])], ,enable_linux_affinity="yes") +if test "x$enable_linux_affinity" = xyes -a "x$cross_compiling" = xno; then AC_MSG_CHECKING([for usable sched_setaffinity]) AC_RUN_IFELSE([ AC_LANG_PROGRAM([[ @@ -225,17 +225,17 @@ if test "x$enable_native_affinity" = xyes -a "x$cross_compiling" = xno; then if (errno == ENOSYS) return 1; ]])], [AC_MSG_RESULT([yes])], - [enable_native_affinity=no + [enable_linux_affinity=no AC_MSG_RESULT([no])]) fi -if test "x$enable_native_affinity" = xyes; then - AC_DEFINE(HAVE_NATIVE_AFFINITY, 1, [Define if native sched_setaffinity and sched_getaffinity are to be used.]) +if test "x$enable_linux_affinity" = xyes; then + AC_DEFINE(HAVE_LINUX_AFFINITY, 1, [Define if Linux sched_setaffinity and sched_getaffinity are to be used.]) fi AC_ARG_ENABLE(hwloc, [AC_HELP_STRING([--enable-hwloc], [enable hwloc support for CPU affinity])],, enable_hwloc="no") if test "x$enable_hwloc" = xyes then - AC_CHECK_LIB([hwloc], [hwloc_linux_get_tid_cpubind], [], [missing_libraries="$missing_libraries libhwloc"]) + AC_CHECK_LIB([hwloc], [hwloc_get_proc_cpubind], [], [missing_libraries="$missing_libraries libhwloc"]) AC_CHECK_HEADERS([hwloc.h],[:], [missing_headers="$missing_headers $ac_header"]) fi diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c index 9c460469..2bc67448 100644 --- a/darwin/DarwinProcess.c +++ b/darwin/DarwinProcess.c @@ -13,6 +13,8 @@ in the source distribution for its full text. #include <string.h> #include <stdio.h> +#include <mach/mach.h> + /*{ #include "Settings.h" #include "DarwinProcessList.h" @@ -69,7 +71,7 @@ void DarwinProcess_setStartTime(Process *proc, struct extern_proc *ep, time_t no strftime(proc->starttime_show, 7, ((proc->starttime_ctime > now - 86400) ? "%R " : "%b%d "), &date); } -char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int show_args ) { +char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int* basenameOffset) { /* This function is from the old Mac version of htop. Originally from ps? */ int mib[3], argmax, nargs, c = 0; size_t size; @@ -167,13 +169,7 @@ char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int show_args ) { /* 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. - */ + *basenameOffset = 0; for ( np = NULL; c < nargs && cp < &procargs[size]; cp++ ) { if ( *cp == '\0' ) { c++; @@ -183,49 +179,11 @@ char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int show_args ) { } /* 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 (*basenameOffset == 0) { + *basenameOffset = cp - sp; } } - } -#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 @@ -235,6 +193,9 @@ char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int show_args ) { /* Empty or unterminated string. */ goto ERROR_B; } + if (*basenameOffset == 0) { + *basenameOffset = np - sp; + } /* Make a copy of the string. */ retval = xStrdup(sp); @@ -248,7 +209,8 @@ ERROR_B: free( procargs ); ERROR_A: retval = xStrdup(k->kp_proc.p_comm); - + *basenameOffset = strlen(retval); + return retval; } @@ -275,35 +237,22 @@ void DarwinProcess_setFromKInfoProc(Process *proc, struct kinfo_proc *ps, time_t 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->tpgid = ps->kp_eproc.e_tpgid; + proc->tgid = proc->pid; 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 = DarwinProcess_getCmdLine(ps, false); - slash = strrchr(proc->comm, '/'); - proc->basenameOffset = (NULL != slash) ? (slash - proc->comm) : 0; + proc->comm = DarwinProcess_getCmdLine(ps, &(proc->basenameOffset)); } /* 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; - } + proc->state = (ep->p_stat == SZOMB) ? 'Z' : '?'; /* Make sure the updated flag is set */ proc->updated = true; @@ -327,8 +276,8 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess *proc, DarwinProcessList proc->super.time = (pti.pti_total_system + pti.pti_total_user) / 10000000; proc->super.nlwp = pti.pti_threadnum; - proc->super.m_size = pti.pti_virtual_size / 1024; - proc->super.m_resident = pti.pti_resident_size / 1024; + proc->super.m_size = pti.pti_virtual_size / 1024 / PAGE_SIZE_KB; + proc->super.m_resident = pti.pti_resident_size / 1024 / PAGE_SIZE_KB; proc->super.majflt = pti.pti_faults; proc->super.percent_mem = (double)pti.pti_resident_size * 100.0 / (double)dpl->host_info.max_mem; @@ -342,3 +291,64 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess *proc, DarwinProcessList dpl->super.runningTasks += pti.pti_numrunning; } } + +/* + * Scan threads for process state information. + * Based on: http://stackoverflow.com/questions/6788274/ios-mac-cpu-usage-for-thread + * and https://github.com/max-horvath/htop-osx/blob/e86692e869e30b0bc7264b3675d2a4014866ef46/ProcessList.c + */ +void DarwinProcess_scanThreads(DarwinProcess *dp) { + Process* proc = (Process*) dp; + kern_return_t ret; + + if (proc->state == 'Z') { + return; + } + + task_t port; + ret = task_for_pid(mach_task_self(), proc->pid, &port); + if (ret != KERN_SUCCESS) { + return; + } + + task_info_data_t tinfo; + mach_msg_type_number_t task_info_count = TASK_INFO_MAX; + ret = task_info(port, TASK_BASIC_INFO, (task_info_t) tinfo, &task_info_count); + if (ret != KERN_SUCCESS) { + return; + } + + thread_array_t thread_list; + mach_msg_type_number_t thread_count; + ret = task_threads(port, &thread_list, &thread_count); + if (ret != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(), port); + return; + } + + integer_t run_state = 999; + for (unsigned int i = 0; i < thread_count; i++) { + thread_info_data_t thinfo; + mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT; + ret = thread_info(thread_list[i], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count); + if (ret == KERN_SUCCESS) { + thread_basic_info_t basic_info_th = (thread_basic_info_t) thinfo; + if (basic_info_th->run_state < run_state) { + run_state = basic_info_th->run_state; + } + mach_port_deallocate(mach_task_self(), thread_list[i]); + } + } + vm_deallocate(mach_task_self(), (vm_address_t) thread_list, sizeof(thread_port_array_t) * thread_count); + mach_port_deallocate(mach_task_self(), port); + + char state = '?'; + switch (run_state) { + case TH_STATE_RUNNING: state = 'R'; break; + case TH_STATE_STOPPED: state = 'S'; break; + case TH_STATE_WAITING: state = 'W'; break; + case TH_STATE_UNINTERRUPTIBLE: state = 'U'; break; + case TH_STATE_HALTED: state = 'H'; break; + } + proc->state = state; +} diff --git a/darwin/DarwinProcess.h b/darwin/DarwinProcess.h index c479acfd..df1a79ff 100644 --- a/darwin/DarwinProcess.h +++ b/darwin/DarwinProcess.h @@ -32,10 +32,17 @@ bool Process_isThread(Process* this); void DarwinProcess_setStartTime(Process *proc, struct extern_proc *ep, time_t now); -char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int show_args ); +char *DarwinProcess_getCmdLine(struct kinfo_proc* k, int* basenameOffset); void DarwinProcess_setFromKInfoProc(Process *proc, struct kinfo_proc *ps, time_t now, bool exists); void DarwinProcess_setFromLibprocPidinfo(DarwinProcess *proc, DarwinProcessList *dpl); +/* + * Scan threads for process state information. + * Based on: http://stackoverflow.com/questions/6788274/ios-mac-cpu-usage-for-thread + * and https://github.com/max-horvath/htop-osx/blob/e86692e869e30b0bc7264b3675d2a4014866ef46/ProcessList.c + */ +void DarwinProcess_scanThreads(DarwinProcess *dp); + #endif diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 7ea89d9f..7492f822 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -168,8 +168,10 @@ void ProcessList_goThroughEntries(ProcessList* super) { for(size_t i = 0; i < count; ++i) { proc = (DarwinProcess *)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, (Process_New)DarwinProcess_new); - DarwinProcess_setFromKInfoProc(&proc->super, ps + i, tv.tv_sec, preExisting); + DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], tv.tv_sec, preExisting); DarwinProcess_setFromLibprocPidinfo(proc, dpl); + + DarwinProcess_scanThreads(proc); super->totalTasks += 1; diff --git a/freebsd/FreeBSDProcess.c b/freebsd/FreeBSDProcess.c index 70cfb954..b0d2c37c 100644 --- a/freebsd/FreeBSDProcess.c +++ b/freebsd/FreeBSDProcess.c @@ -115,7 +115,7 @@ void FreeBSDProcess_writeField(Process* this, RichString* str, ProcessField fiel char buffer[256]; buffer[255] = '\0'; int attr = CRT_colors[DEFAULT_COLOR]; int n = sizeof(buffer) - 1; - switch (field) { + switch ((int) field) { // add FreeBSD-specific fields here case JID: snprintf(buffer, n, Process_pidFormat, fp->jid); break; case JAIL:{ @@ -143,7 +143,7 @@ long FreeBSDProcess_compare(const void* v1, const void* v2) { p2 = (FreeBSDProcess*)v1; p1 = (FreeBSDProcess*)v2; } - switch (settings->sortKey) { + switch ((int) settings->sortKey) { // add FreeBSD-specific fields here case JID: return (p1->jid - p2->jid); diff --git a/freebsd/FreeBSDProcessList.c b/freebsd/FreeBSDProcessList.c index b9359e54..241bee23 100644 --- a/freebsd/FreeBSDProcessList.c +++ b/freebsd/FreeBSDProcessList.c @@ -14,7 +14,9 @@ in the source distribution for its full text. #include <sys/types.h> #include <sys/sysctl.h> #include <sys/user.h> +#include <err.h> #include <fcntl.h> +#include <limits.h> #include <string.h> /*{ @@ -84,14 +86,13 @@ static int MIB_kern_cp_time[2]; static int MIB_kern_cp_times[2]; static int kernelFScale; - ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) { + size_t len; + char errbuf[_POSIX2_LINE_MAX]; FreeBSDProcessList* fpl = xCalloc(1, sizeof(FreeBSDProcessList)); ProcessList* pl = (ProcessList*) fpl; ProcessList_init(pl, Class(FreeBSDProcess), usersTable, pidWhiteList, userId); - size_t len; - // physical memory in system: hw.physmem // physical page size: hw.pagesize // usable pagesize : vm.stats.vm.v_page_size @@ -178,8 +179,10 @@ ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, ui kernelFScale = 2048; } - fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL); - assert(fpl->kd); + fpl->kd = kvm_openfiles(NULL, "/dev/null", NULL, 0, errbuf); + if (fpl->kd == NULL) { + errx(1, "kvm_open: %s", errbuf); + } return pl; } @@ -212,9 +215,6 @@ static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { unsigned long *cp_time_n; // old clicks state unsigned long *cp_time_o; // current clicks state - unsigned long long total_o = 0; - unsigned long long total_n = 0; - unsigned long long total_d = 0; unsigned long cp_time_d[CPUSTATES]; double cp_time_p[CPUSTATES]; @@ -251,6 +251,9 @@ static inline void FreeBSDProcessList_scanCPUTime(ProcessList* pl) { } // diff old vs new + unsigned long long total_o = 0; + unsigned long long total_n = 0; + unsigned long long total_d = 0; for (int s = 0; s < CPUSTATES; s++) { cp_time_d[s] = cp_time_n[s] - cp_time_o[s]; total_o += cp_time_o[s]; @@ -479,17 +482,17 @@ void ProcessList_goThroughEntries(ProcessList* this) { // from FreeBSD source /src/usr.bin/top/machine.c proc->m_size = kproc->ki_size / 1024 / pageSizeKb; proc->m_resident = kproc->ki_rssize; + proc->percent_mem = (proc->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0; proc->nlwp = kproc->ki_numthreads; proc->time = (kproc->ki_runtime + 5000) / 10000; proc->percent_cpu = 100.0 * ((double)kproc->ki_pctcpu / (double)kernelFScale); + proc->percent_mem = 100.0 * (proc->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem); + if (proc->percent_cpu > 0.1) { // system idle process should own all CPU time left regardless of CPU count if ( strcmp("idle", kproc->ki_comm) == 0 ) { isIdleProcess = true; - } else { - if (cpus > 1) - proc->percent_cpu = proc->percent_cpu / (double) cpus; } } if (isIdleProcess == false && proc->percent_cpu >= 99.8) { diff --git a/free |