emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch] system_process_attributes for OpenBSD


From: Omar Polo
Subject: [patch] system_process_attributes for OpenBSD
Date: Fri, 01 Jan 2021 23:29:58 +0100
User-agent: mu4e 1.4.13; emacs 27.1

Hello,

I wanted to try proced, but it doesn't work OOTB on OpenBSD.  On emacs
27.1 (installed from packages) list-system-processes returns nil, but on
emacs built from master correctly returns the list of
pids. process-attributes unfortunately returns nil in all the cases.

The attached patch (against the master branch) adds an implementation of
system_process_attributes for OpenBSD.  First time hacking on emacs, I
tried to follow the style but please excuse if I forgot something :)

It's not possible to access processes information via sysctl, one has to
use kvm.  I studied the sources of top and ps while working on this
patch, and I followed what those programs do.  kvm needs to be
initialised with kvm_open [0]: the downside is that a program shouldn't
call two or more time kvm_open (see the BUGS section in the linked
manpage); so I had to use that ugly hack with a static variable: there
is a more elegant way to handle something like this?

There are five stats that I'm not able to collect (cminflt, cmajflt,
cstime, ctime, thcount), but otherwise process-attributes and proced
seem to work just fine:

    (process-attributes 66968)
    ;; =>
    ((args . "emacs --daemon")
     (pmem . 0.9343402932966782)
     (pcpu . 2.587890625)
     (etime 0 41450 331172 251000)
     (rss . 141820)
     (vsize . 113460)
     (start 24558 64860 215303 0)
     (nice . 20)
     (pri . 24)
     (cutime 0 201 920000 0)
     (time 0 376 790000 0)
     (stime 0 36 190000 0)
     (utime 0 340 600000 0)
     (majflt . 5690)
     (minflt . 3903171)
     (tpgid . -1)
     (sess . 66968)
     (pgrp . 1000)
     (ppid . 1)
     (state . "S")
     (comm . "emacs-27.1")
     (group . "op")
     (egid . 1000)
     (user . "op")
     (euid . 1000))

I'm not sure I got the `state' flag correct, where are they documented?

One last thing, I don't have a copyright assignment and I know very
little about them.  I believe I have to sign one if this patch a chance
to be accepted.  Can someone please fill me in on the details?

Thanks,
Omar Polo

[0]: http://man.openbsd.org/kvm_open
[1]: 
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/sys/sysctl.h?rev=1.213&content-type=text/plain

diff --git a/configure.ac b/configure.ac
index bf768441fe..6e8d4a54e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1574,6 +1574,8 @@ AC_DEFUN
 
   hpux*) LIBS_SYSTEM="-l:libdld.sl" ;;
 
+  openbsd) LIBS_SYSTEM="-lkvm" ;;
+
   qnxnto) LIBS_SYSTEM="-lsocket" ;;
 
   solaris) LIBS_SYSTEM="-lsocket -lnsl" ;;
diff --git a/src/sysdep.c b/src/sysdep.c
index eeb9d18494..f1e99c0b8d 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -53,6 +53,11 @@
 # include <sys/sysctl.h>
 #endif
 
+#if defined __OpenBSD__
+# include <kvm.h>
+# include <sys/proc.h>
+#endif
+
 #ifdef DARWIN_OS
 # include <libproc.h>
 #endif
@@ -2972,6 +2977,14 @@ make_lisp_timeval (struct timeval t)
   return make_lisp_time (timeval_to_timespec (t));
 }
 
+#elif defined __OpenBSD__
+
+static Lisp_Object
+make_lisp_timeval (long sec, long usec)
+{
+  return make_lisp_time(make_timespec(sec, usec * 1000));
+}
+
 #endif
 
 #ifdef GNU_LINUX
@@ -3661,6 +3674,188 @@ system_process_attributes (Lisp_Object pid)
   return attrs;
 }
 
+#elif defined __OpenBSD__
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+  static kvm_t *kd = NULL;
+
+  int proc_id, nentries, fscale, i;
+  int pagesize = getpagesize ();
+  int mib[2];
+  size_t len;
+  double pct;
+  char *ttyname, **argv, *args;
+  struct kinfo_proc *proc;
+  struct passwd *pw;
+  struct group *gr;
+  struct timespec t;
+  struct uvmexp uvmexp;
+
+  Lisp_Object attrs = Qnil;
+  Lisp_Object decoded_comm, decoded_args;
+
+  CHECK_NUMBER (pid);
+  CONS_TO_INTEGER (pid, int, proc_id);
+
+  /* hack */
+  if (kd == NULL)
+    {
+      kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
+      if (kd == NULL)
+       return attrs;
+    }
+
+  proc = kvm_getprocs(kd, KERN_PROC_PID, proc_id, sizeof(*proc), &nentries);
+  if (proc == NULL)
+    return attrs;
+
+  attrs = Fcons (Fcons (Qeuid, INT_TO_INTEGER (proc->p_uid)), attrs);
+
+  block_input ();
+  pw = getpwuid (proc->p_uid);
+  unblock_input ();
+  if (pw)
+    attrs = Fcons (Fcons (Quser, build_string(pw->pw_name)), attrs);
+
+  attrs = Fcons (Fcons (Qegid, INT_TO_INTEGER(proc->p_svgid)), attrs);
+
+  block_input ();
+  gr = getgrgid (proc->p_svgid);
+  unblock_input ();
+  if (gr)
+    attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
+
+  AUTO_STRING (comm, proc->p_comm);
+  decoded_comm = code_convert_string_norecord (comm, Vlocale_coding_system, 0);
+  attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs);
+
+  {
+    char state[2] = {'\0', '\0'};
+    switch (proc->p_stat) {
+    case SRUN:
+      state[0] = 'R';
+      break;
+    case SSLEEP:
+      state[0] = 'S';
+      break;
+    case SSTOP:
+      state[0] = 'T';
+      break;
+    case SZOMB:
+      state[0] = 'Z';
+      break;
+    case SDEAD:
+      state[0] = 'D';
+      break;
+    }
+    attrs = Fcons (Fcons (Qstate, build_string (state)), attrs);
+  }
+
+  attrs = Fcons (Fcons (Qppid, INT_TO_INTEGER (proc->p_ppid)), attrs);
+  attrs = Fcons (Fcons (Qpgrp, INT_TO_INTEGER (proc->p_gid)), attrs);
+  attrs = Fcons (Fcons (Qsess, INT_TO_INTEGER (proc->p_sid)),  attrs);
+
+  block_input ();
+  ttyname = proc->p_tdev == NODEV ? NULL : devname (proc->p_tdev, S_IFCHR);
+  unblock_input ();
+  if (ttyname)
+    attrs = Fcons (Fcons (Qttname, build_string (ttyname)), attrs);
+
+  attrs = Fcons (Fcons (Qtpgid,   INT_TO_INTEGER (proc->p_tpgid)), attrs);
+  attrs = Fcons (Fcons (Qminflt,  INT_TO_INTEGER (proc->p_uru_minflt)),
+                attrs);
+  attrs = Fcons (Fcons (Qmajflt,  INT_TO_INTEGER (proc->p_uru_majflt)),
+                attrs);
+
+  /* FIXME: missing cminflt, cmajflt. */
+
+  attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc->p_uutime_sec,
+                                                  proc->p_uutime_usec)),
+                attrs);
+  attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc->p_ustime_sec,
+                                                  proc->p_ustime_usec)),
+                attrs);
+  t = timespec_add (make_timespec (proc->p_uutime_sec,
+                                  proc->p_uutime_usec * 1000),
+                   make_timespec (proc->p_ustime_sec,
+                                  proc->p_ustime_usec * 1000));
+  attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs);
+
+  attrs = Fcons (Fcons (Qcutime, make_lisp_timeval (proc->p_uctime_sec,
+                                                   proc->p_uctime_usec)),
+                attrs);
+
+  /* FIXME: missing cstime and thus ctime. */
+
+  attrs = Fcons (Fcons (Qpri,   make_fixnum (proc->p_priority)), attrs);
+  attrs = Fcons (Fcons (Qnice,  make_fixnum (proc->p_nice)), attrs);
+
+  /* FIXME: missing thcount (thread count) */
+
+  attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc->p_ustart_sec,
+                                                  proc->p_ustart_usec)),
+                attrs);
+
+  len = (proc->p_vm_tsize + proc->p_vm_dsize + proc->p_vm_ssize) * pagesize >> 
10;
+  attrs = Fcons (Fcons (Qvsize, make_fixnum (len)), attrs);
+
+  attrs = Fcons (Fcons (Qrss,   make_fixnum (proc->p_vm_rssize * pagesize >> 
10)),
+                attrs);
+
+  t = make_timespec (proc->p_ustart_sec,
+                    proc->p_ustart_usec * 1000);
+  t = timespec_sub (current_timespec (), t);
+  attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs);
+
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_FSCALE;
+  len = sizeof (fscale);
+  if (sysctl (mib, 2, &fscale, &len, NULL, 0) != -1)
+    {
+      pct = (double)proc->p_pctcpu / fscale * 100.0;
+      attrs = Fcons (Fcons (Qpcpu, make_float (pct)), attrs);
+    }
+
+  mib[0] = CTL_VM;
+  mib[1] = VM_UVMEXP;
+  len = sizeof (uvmexp);
+  if (sysctl (mib, 2, &uvmexp, &len, NULL, 0) != -1)
+    {
+      pct = (100.0 * (double)proc->p_vm_rssize / uvmexp.npages);
+      attrs = Fcons (Fcons (Qpmem, make_float (pct)), attrs);
+    }
+
+  /* concatenate process argv */
+
+  if ((argv = kvm_getargv(kd, proc, 0)) == NULL)
+    return attrs;
+
+  len = 0;
+  for (i = 0; argv[i] != NULL; ++i)
+    len += strlen(argv[i]) + 1;
+
+  if ((args = calloc(1, len)) == NULL)
+    return attrs;
+
+  for (i = 0; argv[i] != NULL; ++i)
+    {
+      strlcat(args, argv[i], len);
+      if (argv[i+1] != NULL)
+       strlcat(args, " ", len);
+    }
+
+  AUTO_STRING (args_str, args);
+  decoded_args = code_convert_string_norecord (args_str,
+                                              Vlocale_coding_system, 0);
+  attrs = Fcons (Fcons (Qargs, decoded_args), attrs);
+
+  free(args);
+
+  return attrs;
+}
+
 #elif defined DARWIN_OS
 
 Lisp_Object



reply via email to

[Prev in Thread] Current Thread [Next in Thread]