htop

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

htop

Michael McConville-2
I'm trying to port htop to OpenBSD. They recently made it portable and
added FreeBSD and Darwin WIPs, so it's manageable.

Some of the FreeBSD code is directly usable or tweakable. I've been
hacking on it for an hour and I have load average, ncpu, and uptime
working. It builds fine when the FreeBSD config/make sections are simply
copied.

Let me know if you're interested in helping.

Reply | Threaded
Open this post in threaded view
|

Re: htop

Jiri B-2
On Wed, Sep 02, 2015 at 07:33:39PM -0400, Michael McConville wrote:
> I'm trying to port htop to OpenBSD. They recently made it portable and
> added FreeBSD and Darwin WIPs, so it's manageable.
>
> Some of the FreeBSD code is directly usable or tweakable. I've been
> hacking on it for an hour and I have load average, ncpu, and uptime
> working. It builds fine when the FreeBSD config/make sections are simply
> copied.
>
> Let me know if you're interested in helping.

Doesn't it depend on procfs?

j.

Reply | Threaded
Open this post in threaded view
|

Re: htop

Edd Barrett-3
In reply to this post by Michael McConville-2
On Wed, Sep 02, 2015 at 07:33:39PM -0400, Michael McConville wrote:
> Let me know if you're interested in helping.

I would happily help testing of this.

--
Best Regards
Edd Barrett

http://www.theunixzoo.co.uk

Reply | Threaded
Open this post in threaded view
|

Re: htop

Michael McConville-2
In reply to this post by Jiri B-2
Jiri B wrote:

> On Wed, Sep 02, 2015 at 07:33:39PM -0400, Michael McConville wrote:
> > I'm trying to port htop to OpenBSD. They recently made it portable
> > and added FreeBSD and Darwin WIPs, so it's manageable.
> >
> > Some of the FreeBSD code is directly usable or tweakable. I've been
> > hacking on it for an hour and I have load average, ncpu, and uptime
> > working. It builds fine when the FreeBSD config/make sections are
> > simply copied.
> >
> > Let me know if you're interested in helping.
>
> Doesn't it depend on procfs?

The interface lets you gather data pretty much however you want to. I'm
planning on just using whatever top(1) does when possible.

Reply | Threaded
Open this post in threaded view
|

Re: htop

Michael McConville-2
In reply to this post by Edd Barrett-3
Edd Barrett wrote:
> On Wed, Sep 02, 2015 at 07:33:39PM -0400, Michael McConville wrote:
> > Let me know if you're interested in helping.
>
> I would happily help testing of this.

Below is a messy preliminary diff.

I think I have the following working:

 * load averages
 * uptime
 * CPU utilization
 * memory (but not yet buffers or cached)
 * swap

That leaves processes and buffered and cached memory.

Here's the main repo:

        https://github.com/hishamhm/htop



diff --git a/Makefile.am b/Makefile.am
index 8fa3819..b54b9a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -51,6 +51,14 @@ myhtopplatheaders = freebsd/Platform.h freebsd/FreeBSDProcessList.h \
 freebsd/FreeBSDProcess.h freebsd/FreeBSDCRT.h freebsd/Battery.h
 endif
 
+if HTOP_OPENBSD
+myhtopplatsources = openbsd/Platform.c openbsd/OpenBSDProcessList.c \
+openbsd/OpenBSDProcess.c openbsd/OpenBSDCRT.c openbsd/Battery.c
+
+myhtopplatheaders = openbsd/Platform.h openbsd/OpenBSDProcessList.h \
+openbsd/OpenBSDProcess.h openbsd/OpenBSDCRT.h openbsd/Battery.h
+endif
+
 if HTOP_DARWIN
 htop_LDFLAGS += -framework IOKit -framework CoreFoundation
 myhtopplatsources = darwin/Platform.c darwin/DarwinProcess.c \
diff --git a/configure.ac b/configure.ac
index 13b09a6..f865cbf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,6 +33,9 @@ case "$target" in
 *freebsd*)
    my_htop_platform=freebsd
    ;;
+*openbsd*)
+   my_htop_platform=openbsd
+   ;;
 *darwin*)
    my_htop_platform=darwin
    ;;
@@ -168,6 +171,10 @@ if test "$my_htop_platform" = "freebsd"; then
    AC_CHECK_LIB([kvm], [kvm_open], [], [missing_libraries="$missing_libraries libkvm"])
 fi
 
+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_MSG_CHECKING([for usable sched_setaffinity])
@@ -211,6 +218,7 @@ AC_DEFINE_UNQUOTED(COPYRIGHT, "(C) 2004-$year Hisham Muhammad", [Copyright messa
 # ----------------------------------------------------------------------
 AM_CONDITIONAL([HTOP_LINUX], [test "$my_htop_platform" = linux])
 AM_CONDITIONAL([HTOP_FREEBSD], [test "$my_htop_platform" = freebsd])
+AM_CONDITIONAL([HTOP_OPENBSD], [test "$my_htop_platform" = openbsd])
 AM_CONDITIONAL([HTOP_DARWIN], [test "$my_htop_platform" = darwin])
 AM_CONDITIONAL([HTOP_UNSUPPORTED], [test "$my_htop_platform" = unsupported])
 AC_SUBST(my_htop_platform)
diff --git a/openbsd/Battery.c b/openbsd/Battery.c
new file mode 100644
index 0000000..37ac815
--- /dev/null
+++ b/openbsd/Battery.c
@@ -0,0 +1,15 @@
+/*
+htop - openbsd/Battery.c
+(C) 2015 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "BatteryMeter.h"
+
+void Battery_getData(double* level, ACPresence* isOnAC) {
+   // TODO
+   *level = -1;
+   *isOnAC = AC_ERROR;
+}
+
diff --git a/openbsd/Battery.h b/openbsd/Battery.h
new file mode 100644
index 0000000..8ec41e3
--- /dev/null
+++ b/openbsd/Battery.h
@@ -0,0 +1,15 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_Battery
+#define HEADER_Battery
+/*
+htop - openbsd/Battery.h
+(C) 2015 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+void Battery_getData(double* level, ACPresence* isOnAC);
+
+
+#endif
diff --git a/openbsd/OpenBSDCRT.c b/openbsd/OpenBSDCRT.c
new file mode 100644
index 0000000..c4e65ee
--- /dev/null
+++ b/openbsd/OpenBSDCRT.c
@@ -0,0 +1,21 @@
+/*
+htop - UnsupportedCRT.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "config.h"
+#include "CRT.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+void CRT_handleSIGSEGV(int sgn) {
+   (void) sgn;
+   CRT_done();
+   fprintf(stderr, "\n\nhtop " VERSION " aborting.\n");
+   fprintf(stderr, "\nUnfortunately, you seem to be using an unsupported platform!");
+   fprintf(stderr, "\nPlease contact your platform package mantainer!\n\n");
+   abort();
+}
+
diff --git a/openbsd/OpenBSDCRT.h b/openbsd/OpenBSDCRT.h
new file mode 100644
index 0000000..3c808ca
--- /dev/null
+++ b/openbsd/OpenBSDCRT.h
@@ -0,0 +1,15 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_UnsupportedCRT
+#define HEADER_UnsupportedCRT
+/*
+htop - UnsupportedCRT.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+void CRT_handleSIGSEGV(int sgn);
+
+
+#endif
diff --git a/openbsd/OpenBSDProcess.c b/openbsd/OpenBSDProcess.c
new file mode 100644
index 0000000..bdf3b5c
--- /dev/null
+++ b/openbsd/OpenBSDProcess.c
@@ -0,0 +1,233 @@
+/*
+htop - OpenBSDProcess.c
+(C) 2015 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Process.h"
+#include "ProcessList.h"
+#include "OpenBSDProcess.h"
+#include "Platform.h"
+#include "CRT.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+/*{
+
+typedef enum OpenBSDProcessFields {
+   // Add platform-specific fields here, with ids >= 100
+   LAST_PROCESSFIELD = 100,
+} OpenBSDProcessField;
+
+typedef struct OpenBSDProcess_ {
+   Process super;
+} OpenBSDProcess;
+
+#ifndef Process_isKernelThread
+#define Process_isKernelThread(_process) (_process->pgrp == 0)
+#endif
+
+#ifndef Process_isUserlandThread
+#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
+#endif
+
+}*/
+
+ProcessClass OpenBSDProcess_class = {
+   .super = {
+      .extends = Class(Process),
+      .display = Process_display,
+      .delete = Process_delete,
+      .compare = OpenBSDProcess_compare
+   },
+   .writeField = (Process_WriteField) OpenBSDProcess_writeField,
+};
+
+ProcessFieldData Process_fields[] = {
+   [0] = {
+   .name = "",
+   .title = NULL,
+   .description = NULL,
+   .flags = 0, },
+   [PID] = {
+   .name = "PID",
+   .title = "    PID ",
+   .description = "Process/thread ID",
+   .flags = 0, },
+   [COMM] = {
+   .name = "Command",
+   .title = "Command ",
+   .description = "Command line",
+   .flags = 0, },
+   [STATE] = {
+   .name = "STATE",
+   .title = "S ",
+   .description = "Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging)",
+   .flags = 0, },
+   [PPID] = {
+   .name = "PPID",
+   .title = "   PPID ",
+   .description = "Parent process ID",
+   .flags = 0, },
+   [PGRP] = {
+   .name = "PGRP",
+   .title = "   PGRP ",
+   .description = "Process group ID",
+   .flags = 0, },
+   [SESSION] = {
+   .name = "SESSION",
+   .title = "   SESN ",
+   .description = "Process's session ID",
+   .flags = 0, },
+   [TTY_NR] = {
+   .name = "TTY_NR",
+   .title = "  TTY ",
+   .description = "Controlling terminal",
+   .flags = 0, },
+   [TPGID] = {
+   .name = "TPGID",
+   .title = "  TPGID ",
+   .description = "Process ID of the fg process group of the controlling terminal",
+   .flags = 0, },
+   [MINFLT] = {
+   .name = "MINFLT",
+   .title = "     MINFLT ",
+   .description = "Number of minor faults which have not required loading a memory page from disk",
+   .flags = 0, },
+   [MAJFLT] = {
+   .name = "MAJFLT",
+   .title = "     MAJFLT ",
+   .description = "Number of major faults which have required loading a memory page from disk",
+   .flags = 0, },
+   [PRIORITY] = {
+   .name = "PRIORITY",
+   .title = "PRI ",
+   .description = "Kernel's internal priority for the process",
+   .flags = 0, },
+   [NICE] = {
+   .name = "NICE",
+   .title = " NI ",
+   .description = "Nice value (the higher the value, the more it lets other processes take priority)",
+   .flags = 0, },
+   [STARTTIME] = {
+   .name = "STARTTIME",
+   .title = "START ",
+   .description = "Time the process was started",
+   .flags = 0, },
+   [PROCESSOR] = {
+   .name = "PROCESSOR",
+   .title = "CPU ",
+   .description = "Id of the CPU the process last executed on",
+   .flags = 0, },
+   [M_SIZE] = {
+   .name = "M_SIZE",
+   .title = " VIRT ",
+   .description = "Total program size in virtual memory",
+   .flags = 0, },
+   [M_RESIDENT] = {
+   .name = "M_RESIDENT",
+   .title = "  RES ",
+   .description = "Resident set size, size of the text and data sections, plus stack usage",
+   .flags = 0, },
+   [ST_UID] = {
+   .name = "ST_UID",
+   .title = " UID ",
+   .description = "User ID of the process owner",
+   .flags = 0, },
+   [PERCENT_CPU] = {
+   .name = "PERCENT_CPU",
+   .title = "CPU% ",
+   .description = "Percentage of the CPU time the process used in the last sampling",
+   .flags = 0, },
+   [PERCENT_MEM] = {
+   .name = "PERCENT_MEM",
+   .title = "MEM% ",
+   .description = "Percentage of the memory the process is using, based on resident memory size",
+   .flags = 0, },
+   [USER] = {
+   .name = "USER",
+   .title = "USER      ",
+   .description = "Username of the process owner (or user ID if name cannot be determined)",
+   .flags = 0, },
+   [TIME] = {
+   .name = "TIME",
+   .title = "  TIME+  ",
+   .description = "Total time the process has spent in user and system time",
+   .flags = 0, },
+   [NLWP] = {
+   .name = "NLWP",
+   .title = "NLWP ",
+   .description = "Number of threads in the process",
+   .flags = 0, },
+   [TGID] = {
+   .name = "TGID",
+   .title = "   TGID ",
+   .description = "Thread group ID (i.e. process ID)",
+   .flags = 0, },
+   [LAST_PROCESSFIELD] = {
+   .name = "*** report bug! ***",
+   .title = NULL,
+   .description = NULL,
+   .flags = 0, },
+};
+
+ProcessPidColumn Process_pidColumns[] = {
+   { .id = PID, .label = "PID" },
+   { .id = PPID, .label = "PPID" },
+   { .id = TPGID, .label = "TPGID" },
+   { .id = TGID, .label = "TGID" },
+   { .id = PGRP, .label = "PGRP" },
+   { .id = SESSION, .label = "SESN" },
+   { .id = 0, .label = NULL },
+};
+
+OpenBSDProcess* OpenBSDProcess_new(Settings* settings) {
+   OpenBSDProcess* this = calloc(sizeof(OpenBSDProcess), 1);
+   Object_setClass(this, Class(OpenBSDProcess));
+   Process_init(&this->super, settings);
+   return this;
+}
+
+void Process_delete(Object* cast) {
+   OpenBSDProcess* this = (OpenBSDProcess*) cast;
+   Process_done((Process*)cast);
+   free(this);
+}
+
+void OpenBSDProcess_writeField(Process* this, RichString* str, ProcessField field) {
+   //OpenBSDProcess* fp = (OpenBSDProcess*) this;
+   char buffer[256]; buffer[255] = '\0';
+   int attr = CRT_colors[DEFAULT_COLOR];
+   //int n = sizeof(buffer) - 1;
+   switch (field) {
+   // add OpenBSD-specific fields here
+   default:
+      Process_writeField(this, str, field);
+      return;
+   }
+   RichString_append(str, attr, buffer);
+}
+
+long OpenBSDProcess_compare(const void* v1, const void* v2) {
+   OpenBSDProcess *p1, *p2;
+   Settings *settings = ((Process*)v1)->settings;
+   if (settings->direction == 1) {
+      p1 = (OpenBSDProcess*)v1;
+      p2 = (OpenBSDProcess*)v2;
+   } else {
+      p2 = (OpenBSDProcess*)v1;
+      p1 = (OpenBSDProcess*)v2;
+   }
+   switch (settings->sortKey) {
+   // add OpenBSD-specific fields here
+   default:
+      return Process_compare(v1, v2);
+   }
+}
+
+bool Process_isThread(Process* this) {
+   return (Process_isKernelThread(this));
+}
diff --git a/openbsd/OpenBSDProcess.h b/openbsd/OpenBSDProcess.h
new file mode 100644
index 0000000..491f4c9
--- /dev/null
+++ b/openbsd/OpenBSDProcess.h
@@ -0,0 +1,47 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_OpenBSDProcess
+#define HEADER_OpenBSDProcess
+/*
+htop - OpenBSDProcess.h
+(C) 2015 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+typedef enum OpenBSDProcessFields {
+   // Add platform-specific fields here, with ids >= 100
+   LAST_PROCESSFIELD = 100,
+} OpenBSDProcessField;
+
+typedef struct OpenBSDProcess_ {
+   Process super;
+} OpenBSDProcess;
+
+#ifndef Process_isKernelThread
+#define Process_isKernelThread(_process) (_process->pgrp == 0)
+#endif
+
+#ifndef Process_isUserlandThread
+#define Process_isUserlandThread(_process) (_process->pid != _process->tgid)
+#endif
+
+
+extern ProcessClass OpenBSDProcess_class;
+
+extern ProcessFieldData Process_fields[];
+
+extern ProcessPidColumn Process_pidColumns[];
+
+OpenBSDProcess* OpenBSDProcess_new(Settings* settings);
+
+void Process_delete(Object* cast);
+
+void OpenBSDProcess_writeField(Process* this, RichString* str, ProcessField field);
+
+long OpenBSDProcess_compare(const void* v1, const void* v2);
+
+bool Process_isThread(Process* this);
+
+#endif
diff --git a/openbsd/OpenBSDProcessList.c b/openbsd/OpenBSDProcessList.c
new file mode 100644
index 0000000..d9d6c23
--- /dev/null
+++ b/openbsd/OpenBSDProcessList.c
@@ -0,0 +1,207 @@
+/*
+htop - OpenBSDProcessList.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "ProcessList.h"
+#include "OpenBSDProcessList.h"
+#include "OpenBSDProcess.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <string.h>
+
+/*{
+
+#include <kvm.h>
+
+typedef struct CPUData_ {
+   unsigned long long int totalTime;
+   unsigned long long int totalPeriod;
+} CPUData;
+
+typedef struct OpenBSDProcessList_ {
+   ProcessList super;
+   kvm_t* kd;
+
+   CPUData* cpus;
+
+} OpenBSDProcessList;
+
+}*/
+
+static int MIB_hw_physmem[2];
+
+static int pageSizeKb;
+
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
+   OpenBSDProcessList* fpl = calloc(1, sizeof(OpenBSDProcessList));
+   ProcessList* pl = (ProcessList*) fpl;
+   ProcessList_init(pl, Class(OpenBSDProcess), usersTable, pidWhiteList, userId);
+
+   pl->cpuCount = 1;    // default to 1 on sysctl() error
+   int mib[2] = { CTL_HW, HW_NCPU };
+   size_t size = sizeof(pl->cpuCount);
+   int err = sysctl(mib, 2, &pl->cpuCount, &size, NULL, 0);
+   fpl->cpus = realloc(fpl->cpus, pl->cpuCount * sizeof(CPUData));
+
+   for (int i = 0; i < pl->cpuCount; i++) {
+      fpl->cpus[i].totalTime = 1;
+      fpl->cpus[i].totalPeriod = 1;
+   }
+  
+   fpl->kd = kvm_open(NULL, "/dev/null", NULL, 0, NULL);
+   assert(fpl->kd);
+
+   return pl;
+}
+
+void ProcessList_delete(ProcessList* this) {
+ /*
+   const OpenBSDProcessList* fpl = (OpenBSDProcessList*) this;
+   if (fpl->kd) kvm_close(fpl->kd);
+  
+   ProcessList_done(this);
+   free(this);
+   */
+}
+
+static inline void OpenBSDProcessList_scanMemoryInfo(ProcessList* pl) {
+ /*
+   const OpenBSDProcessList* fpl = (OpenBSDProcessList*) pl;
+  
+   size_t len = sizeof(pl->totalMem);
+   sysctl(MIB_hw_physmem, 2, &(pl->totalMem), &len, NULL, 0);
+   pl->totalMem /= 1024;
+   sysctl(MIB_vm_stats_vm_v_wire_count, 4, &(pl->usedMem), &len, NULL, 0);
+   pl->usedMem *= pageSizeKb;
+   pl->freeMem = pl->totalMem - pl->usedMem;
+   sysctl(MIB_vm_stats_vm_v_cache_count, 4, &(pl->cachedMem), &len, NULL, 0);
+   pl->cachedMem *= pageSizeKb;
+  
+   struct kvm_swap swap[16];
+   int nswap = kvm_getswapinfo(fpl->kd, swap, sizeof(swap)/sizeof(swap[0]), 0);
+   pl->totalSwap = 0;
+   pl->usedSwap = 0;
+   for (int i = 0; i < nswap; i++) {
+      pl->totalSwap += swap[i].ksw_total;
+      pl->usedSwap += swap[i].ksw_used;
+   }
+   pl->totalSwap *= pageSizeKb;
+   pl->usedSwap *= pageSizeKb;
+  
+   pl->sharedMem = 0;  // currently unused
+   pl->buffersMem = 0; // not exposed to userspace
+   */
+}
+
+char* OpenBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd) {
+ /*
+   char** argv = kvm_getargv(kd, kproc, 0);
+   if (!argv) {
+      return strdup(kproc->ki_comm);
+   }
+   int len = 0;
+   for (int i = 0; argv[i]; i++) {
+      len += strlen(argv[i]) + 1;
+   }
+   char* comm = malloc(len * sizeof(char));
+   char* at = comm;
+   *basenameEnd = 0;
+   for (int i = 0; argv[i]; i++) {
+      at = stpcpy(at, argv[i]);
+      if (!*basenameEnd) {
+         *basenameEnd = at - comm;
+      }
+      *at = ' ';
+      at++;
+   }
+   at--;
+   *at = '\0';
+   return comm;
+   */
+ return "proc-name-here";
+}
+
+void ProcessList_goThroughEntries(ProcessList* this) {
+   /*
+   OpenBSDProcessList* fpl = (OpenBSDProcessList*) this;
+   Settings* settings = this->settings;
+   bool hideKernelThreads = settings->hideKernelThreads;
+   bool hideUserlandThreads = settings->hideUserlandThreads;
+  
+   OpenBSDProcessList_scanMemoryInfo(this);
+  
+   int count = 0;
+   struct kinfo_proc* kprocs = kvm_getprocs(fpl->kd, KERN_PROC_ALL, 0, &count);
+  
+   for (int i = 0; i < count; i++) {
+      struct kinfo_proc* kproc = &kprocs[i];
+      
+      bool preExisting = false;
+      Process* proc = ProcessList_getProcess(this, kproc->ki_pid, &preExisting, (Process_New) OpenBSDProcess_new);
+      OpenBSDProcess* fp = (OpenBSDProcess*) proc;
+
+      proc->show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
+      
+      if (!preExisting) {
+         proc->ppid = kproc->ki_ppid;
+         proc->tpgid = kproc->ki_tpgid;
+         proc->tgid = kproc->ki_pid;
+         proc->session = kproc->ki_sid;
+         proc->tty_nr = kproc->ki_tdev;
+         proc->pgrp = kproc->ki_pgid;
+         proc->st_uid = kproc->ki_uid;
+         proc->starttime_ctime = kproc->ki_start.tv_sec;
+         proc->user = UsersTable_getRef(this->usersTable, proc->st_uid);
+         ProcessList_add((ProcessList*)this, proc);
+         proc->comm = OpenBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
+      } else {
+         if (settings->updateProcessNames) {
+            free(proc->comm);
+            proc->comm = OpenBSDProcessList_readProcessName(fpl->kd, kproc, &proc->basenameOffset);
+         }
+      }
+
+      proc->m_size = kproc->ki_size / pageSizeKb / 1000;
+      proc->m_resident = kproc->ki_rssize; // * pageSizeKb;
+      proc->nlwp = kproc->ki_numthreads;
+      proc->time = (kproc->ki_runtime + 5000) / 10000;
+      proc->priority = kproc->ki_pri.pri_level - PZERO;
+      if (kproc->ki_pri.pri_class == PRI_TIMESHARE) {
+         proc->nice = kproc->ki_nice - NZERO;
+      } else if (PRI_IS_REALTIME(kproc->ki_pri.pri_class)) {
+         proc->nice = PRIO_MIN - 1 - (PRI_MAX_REALTIME - kproc->ki_pri.pri_level);
+      } else {
+         proc->nice = PRIO_MAX + 1 + kproc->ki_pri.pri_level - PRI_MIN_IDLE;
+      }
+
+      switch (kproc->ki_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;
+      case SWAIT:  proc->state = 'D'; break;
+      case SLOCK:  proc->state = 'L'; break;
+      default:     proc->state = '?';
+      }
+
+      if (Process_isKernelThread(proc)) {
+         this->kernelThreads++;
+      }
+      
+      this->totalTasks++;
+      if (proc->state == 'R')
+         this->runningTasks++;
+      proc->updated = true;
+   }
+   */
+}
diff --git a/openbsd/OpenBSDProcessList.h b/openbsd/OpenBSDProcessList.h
new file mode 100644
index 0000000..c56f2a1
--- /dev/null
+++ b/openbsd/OpenBSDProcessList.h
@@ -0,0 +1,37 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_OpenBSDProcessList
+#define HEADER_OpenBSDProcessList
+/*
+htop - OpenBSDProcessList.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+
+#include <kvm.h>
+
+typedef struct CPUData_ {
+   unsigned long long int totalTime;
+   unsigned long long int totalPeriod;
+} CPUData;
+
+typedef struct OpenBSDProcessList_ {
+   ProcessList super;
+   kvm_t* kd;
+
+   CPUData* cpus;
+
+} OpenBSDProcessList;
+
+
+ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId);
+
+void ProcessList_delete(ProcessList* this);
+
+char* OpenBSDProcessList_readProcessName(kvm_t* kd, struct kinfo_proc* kproc, int* basenameEnd);
+
+void ProcessList_goThroughEntries(ProcessList* this);
+
+#endif
diff --git a/openbsd/Platform.c b/openbsd/Platform.c
new file mode 100644
index 0000000..db8dd69
--- /dev/null
+++ b/openbsd/Platform.c
@@ -0,0 +1,258 @@
+/*
+htop - openbsd/Platform.c
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "Platform.h"
+#include "Meter.h"
+#include "CPUMeter.h"
+#include "MemoryMeter.h"
+#include "SwapMeter.h"
+#include "TasksMeter.h"
+#include "LoadAverageMeter.h"
+#include "UptimeMeter.h"
+#include "ClockMeter.h"
+#include "HostnameMeter.h"
+#include "OpenBSDProcess.h"
+#include "OpenBSDProcessList.h"
+
+// for CPU state constants
+#include <sys/sched.h>
+
+#include <uvm/uvmexp.h>
+#include <sys/param.h>
+#include <sys/swap.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <time.h>
+
+/*{
+#include "Action.h"
+#include "BatteryMeter.h"
+
+extern ProcessFieldData Process_fields[];
+
+}*/
+
+#define MAXCPU 256
+// XXX: probably should be a struct member
+static int64_t old_v[MAXCPU][5];
+
+/*
+ * percentages(cnt, out, new, old, diffs) - calculate percentage change
+ * between array "old" and "new", putting the percentages in "out".
+ * "cnt" is size of each array and "diffs" is used for scratch space.
+ * The array "old" is updated on each call.
+ * The routine assumes modulo arithmetic.  This function is especially
+ * useful on BSD machines for calculating cpu state percentages.
+ */
+static int percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs) {
+ int64_t change, total_change, *dp, half_total;
+ int i;
+
+ /* initialization */
+ total_change = 0;
+ dp = diffs;
+
+ /* calculate changes for each state and the overall change */
+ for (i = 0; i < cnt; i++) {
+ if ((change = *new - *old) < 0) {
+ /* this only happens when the counter wraps */
+ change = INT64_MAX - *old + *new;
+ }
+ total_change += (*dp++ = change);
+ *old++ = *new++;
+ }
+
+ /* avoid divide by zero potential */
+ if (total_change == 0)
+ total_change = 1;
+
+ /* calculate percentages based on overall change, rounding up */
+ half_total = total_change / 2l;
+ for (i = 0; i < cnt; i++)
+ *out++ = ((*diffs++ * 1000 + half_total) / total_change);
+
+ /* return the total in case the caller wants to use it */
+ return (total_change);
+}
+
+ProcessField Platform_defaultFields[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
+
+int Platform_numberOfFields = LAST_PROCESSFIELD;
+
+void Platform_setBindings(Htop_Action* keys) {
+   (void) keys;
+}
+
+MeterClass* Platform_meterTypes[] = {
+   &CPUMeter_class,
+   &ClockMeter_class,
+   &LoadAverageMeter_class,
+   &LoadMeter_class,
+   &MemoryMeter_class,
+   &SwapMeter_class,
+   &TasksMeter_class,
+   &UptimeMeter_class,
+   &BatteryMeter_class,
+   &HostnameMeter_class,
+   &AllCPUsMeter_class,
+   &AllCPUs2Meter_class,
+   &LeftCPUsMeter_class,
+   &RightCPUsMeter_class,
+   &LeftCPUs2Meter_class,
+   &RightCPUs2Meter_class,
+   &BlankMeter_class,
+   NULL
+};
+
+// preserved from FreeBSD port
+int Platform_getUptime() {
+   struct timeval bootTime, currTime;
+   int mib[2] = { CTL_KERN, KERN_BOOTTIME };
+   size_t size = sizeof(bootTime);
+  
+   int err = sysctl(mib, 2, &bootTime, &size, NULL, 0);
+   if (err) {
+      return -1;
+   }
+   gettimeofday(&currTime, NULL);
+
+   return (int) difftime(currTime.tv_sec, bootTime.tv_sec);
+}
+
+void Platform_getLoadAverage(double* one, double* five, double* fifteen) {
+   struct loadavg loadAverage;
+   int mib[2] = { CTL_VM, VM_LOADAVG };
+   size_t size = sizeof(loadAverage);
+  
+   int err = sysctl(mib, 2, &loadAverage, &size, NULL, 0);
+   if (err) {
+      *one = 0;
+      *five = 0;
+      *fifteen = 0;
+      return;
+   }
+   *one     = (double) loadAverage.ldavg[0] / loadAverage.fscale;
+   *five    = (double) loadAverage.ldavg[1] / loadAverage.fscale;
+   *fifteen = (double) loadAverage.ldavg[2] / loadAverage.fscale;
+}
+
+int Platform_getMaxPid() {
+   // this is hard-coded in sys/sys/proc.h - no sysctl exists
+   return 32766;
+}
+
+double Platform_setCPUValues(Meter* this, int cpu) {
+ int i;
+ double perc;
+
+ OpenBSDProcessList* pl = (OpenBSDProcessList*) this->pl;
+ CPUData* cpuData = &(pl->cpus[cpu]);
+ int64_t new_v[CPUSTATES], diff_v[CPUSTATES], scratch_v[CPUSTATES];
+ double *v = this->values;
+ size_t size = sizeof(double) * CPUSTATES;
+ int mib[] = { CTL_KERN, KERN_CPTIME2, cpu-1 };
+ if (sysctl(mib, 3, new_v, &size, NULL, 0) == -1) {
+ puts("err!");
+ //return 0.;
+ }
+
+ // XXX: why?
+ cpuData->totalPeriod = 1;
+
+ percentages(CPUSTATES, diff_v, new_v,
+ (int64_t *)old_v[cpu-1], scratch_v);
+
+ for (i = 0; i < CPUSTATES; i++) {
+ old_v[cpu-1][i] = new_v[i];
+ v[i] = diff_v[i] / 10.;
+ }
+
+ Meter_setItems(this, 4);
+
+ perc = v[0] + v[1] + v[2] + v[3];
+
+ if (perc <= 100. && perc >= 0.) {
+ return perc;
+ } else {
+ return 12.34;
+ }
+}
+
+/*
+ * Adapted from OpenBSD's top(1)
+ */
+void Platform_setMemoryValues(Meter* this) {
+   ProcessList* pl = (ProcessList*) this->pl;
+   static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
+   struct uvmexp uvmexp;
+   size_t size = sizeof(uvmexp);
+   int kb_pagesize;
+
+   if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) < 0) {
+   bzero(&uvmexp, sizeof(uvmexp));
+   }
+
+   kb_pagesize = uvmexp.pagesize / 1024;
+   pl->usedMem = uvmexp.active * kb_pagesize;
+   pl->totalMem = uvmexp.npages * kb_pagesize;
+
+   // cargo-culted - not sure of the sense behind the indirection here
+   this->total = pl->totalMem;
+   this->values[0] = pl->usedMem;
+}
+
+/*
+ * Taken almost directly from OpenBSD's top(1)
+ */
+void Platform_setSwapValues(Meter* this) {
+ ProcessList* pl = (ProcessList*) this->pl;
+ struct swapent *swdev;
+ unsigned long long int total, used;
+ int nswap, rnswap, i;
+ nswap = swapctl(SWAP_NSWAP, 0, 0);
+ if (nswap == 0) {
+ return;
+ }
+
+ swdev = calloc(nswap, sizeof(*swdev));
+ if (swdev == NULL) {
+ return;
+ }
+
+ rnswap = swapctl(SWAP_STATS, swdev, nswap);
+ if (rnswap == -1) {
+ free(swdev);
+ return;
+ }
+
+ // if rnswap != nswap, then what?
+
+ /* Total things up */
+ total = used = 0;
+ for (i = 0; i < nswap; i++) {
+ if (swdev[i].se_flags & SWF_ENABLE) {
+ used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
+ total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
+ }
+ }
+
+ this->total = pl->totalSwap = total;
+ this->values[0] = pl->usedSwap = used;
+
+ free(swdev);
+}
+
+void Platform_setTasksValues(Meter* this) {
+   // TODO
+}
diff --git a/openbsd/Platform.h b/openbsd/Platform.h
new file mode 100644
index 0000000..506ea8d
--- /dev/null
+++ b/openbsd/Platform.h
@@ -0,0 +1,59 @@
+/* Do not edit this file. It was automatically generated. */
+
+#ifndef HEADER_Platform
+#define HEADER_Platform
+/*
+htop - openbsd/Platform.h
+(C) 2014 Hisham H. Muhammad
+Released under the GNU GPL, see the COPYING file
+in the source distribution for its full text.
+*/
+
+// for CPU state constants
+
+#include "Action.h"
+#include "BatteryMeter.h"
+
+extern ProcessFieldData Process_fields[];
+
+
+#define MAXCPU 256
+// XXX: probably should be a struct member
+/*
+ * percentages(cnt, out, new, old, diffs) - calculate percentage change
+ * between array "old" and "new", putting the percentages in "out".
+ * "cnt" is size of each array and "diffs" is used for scratch space.
+ * The array "old" is updated on each call.
+ * The routine assumes modulo arithmetic.  This function is especially
+ * useful on BSD machines for calculating cpu state percentages.
+ */
+extern ProcessField Platform_defaultFields[];
+
+extern int Platform_numberOfFields;
+
+void Platform_setBindings(Htop_Action* keys);
+
+extern MeterClass* Platform_meterTypes[];
+
+// preserved from FreeBSD port
+int Platform_getUptime();
+
+void Platform_getLoadAverage(double* one, double* five, double* fifteen);
+
+int Platform_getMaxPid();
+
+double Platform_setCPUValues(Meter* this, int cpu);
+
+/*
+ * Adapted from OpenBSD's top(1)
+ */
+void Platform_setMemoryValues(Meter* this);
+
+/*
+ * Taken almost directly from OpenBSD's top(1)
+ */
+void Platform_setSwapValues(Meter* this);
+
+void Platform_setTasksValues(Meter* this);
+
+#endif

Reply | Threaded
Open this post in threaded view
|

Re: htop

Michael McConville-2
In reply to this post by Edd Barrett-3
Edd Barrett wrote:
> On Wed, Sep 02, 2015 at 07:33:39PM -0400, Michael McConville wrote:
> > Let me know if you're interested in helping.
>
> I would happily help testing of this.

Here's my fork:

        https://github.com/mmcco/htop

And my pull request:

        https://github.com/hishamhm/htop/pull/274

It's an alpha that I hacked together in spare hours, so don't expect
miracles. However, I think everything on the default screen is working
now. It'll probably be merged soon.

I used code and logic from top(1) and ps(1) when possible, so thanks to
the people who wrote and maintain those. I gave them credit in the code
as well.