Merge branch 'collectd-5.4'
authorMarc Fournier <marc.fournier@camptocamp.com>
Fri, 15 Jan 2016 16:19:31 +0000 (17:19 +0100)
committerMarc Fournier <marc.fournier@camptocamp.com>
Fri, 15 Jan 2016 16:19:31 +0000 (17:19 +0100)
1  2 
src/processes.c

diff --combined src/processes.c
@@@ -25,7 -25,7 +25,7 @@@
   *
   * Authors:
   *   Lyonel Vincent <lyonel at ezix.org>
 - *   Florian octo Forster <octo at verplant.org>
 + *   Florian octo Forster <octo at collectd.org>
   *   Oleg King <king2 at kaluga.ru>
   *   Sebastian Harl <sh at tokkee.org>
   *   Andrés J. Díaz <ajdiaz at connectical.com>
  #  endif
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
  #  include <kvm.h>
  #  include <sys/param.h>
  #  include <sys/sysctl.h>
  #  include <sys/user.h>
  #  include <sys/proc.h>
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
  #  include <procinfo.h>
  # include <kstat.h>
  #endif
  
 -#ifndef ARG_MAX
 -#  define ARG_MAX 4096
 +#ifndef CMDLINE_BUFFER_SIZE
 +# if defined(ARG_MAX) && (ARG_MAX < 4096)
 +#  define CMDLINE_BUFFER_SIZE ARG_MAX
 +# else
 +#  define CMDLINE_BUFFER_SIZE 4096
 +# endif
  #endif
  
  typedef struct procstat_entry_s
        derive_t io_syscr;
        derive_t io_syscw;
  
 +      derive_t cswitch_vol;
 +      derive_t cswitch_invol;
 +
        struct procstat_entry_s *next;
  } procstat_entry_t;
  
@@@ -214,17 -207,12 +214,17 @@@ typedef struct procsta
        derive_t io_syscr;
        derive_t io_syscw;
  
 +      derive_t cswitch_vol;
 +      derive_t cswitch_invol;
 +
        struct procstat   *next;
        struct procstat_entry_s *instances;
  } procstat_t;
  
  static procstat_t *list_head_g = NULL;
  
 +static _Bool report_ctx_switch = 0;
 +
  #if HAVE_THREAD_INFO
  static mach_port_t port_host_self;
  static mach_port_t port_task_self;
@@@ -237,9 -225,9 +237,9 @@@ static mach_msg_type_number_t     pset_
  static long pagesize_g;
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
  static int pagesize;
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
  static  struct procentry64 procentry[MAXPROCENTRY];
@@@ -287,8 -275,8 +287,8 @@@ static void ps_list_register (const cha
                if (status != 0)
                {
                        DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
 -                      sfree(new->re);
 -                      sfree(new);
 +                      sfree (new->re);
 +                      sfree (new);
                        return;
                }
        }
@@@ -407,8 -395,6 +407,8 @@@ static void ps_list_add (const char *na
                pse->io_wchar   = entry->io_wchar;
                pse->io_syscr   = entry->io_syscr;
                pse->io_syscw   = entry->io_syscw;
 +              pse->cswitch_vol   = entry->cswitch_vol;
 +              pse->cswitch_invol = entry->cswitch_invol;
  
                ps->num_proc   += pse->num_proc;
                ps->num_lwp    += pse->num_lwp;
                ps->io_syscr   += ((pse->io_syscr == -1)?0:pse->io_syscr);
                ps->io_syscw   += ((pse->io_syscw == -1)?0:pse->io_syscw);
  
 +              ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
 +              ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
 +
                if ((entry->vmem_minflt_counter == 0)
                                && (entry->vmem_majflt_counter == 0))
                {
@@@ -522,8 -505,6 +522,8 @@@ static void ps_list_reset (void
                ps->io_wchar = -1;
                ps->io_syscr = -1;
                ps->io_syscw = -1;
 +              ps->cswitch_vol   = -1;
 +              ps->cswitch_invol = -1;
  
                pse_prev = NULL;
                pse = ps->instances;
@@@ -608,10 -589,6 +608,10 @@@ static int ps_config (oconfig_item_t *c
                        ps_list_register (c->values[0].value.string,
                                        c->values[1].value.string);
                }
 +              else if (strcasecmp (c->key, "CollectContextSwitch") == 0)
 +              {
 +                      cf_util_get_boolean (c, &report_ctx_switch);
 +              }
                else
                {
                        ERROR ("processes plugin: The `%s' configuration option is not "
@@@ -658,9 -635,9 +658,9 @@@ static int ps_init (void
                        pagesize_g, CONFIG_HZ);
  /* #endif KERNEL_LINUX */
  
 -#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
 +#elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
        pagesize = getpagesize();
 -/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
 +/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD) */
  
  #elif HAVE_PROCINFO_H
        pagesize = getpagesize();
@@@ -761,36 -738,19 +761,36 @@@ static void ps_submit_proc_list (procst
                plugin_dispatch_values (&vl);
        }
  
 +      if ( report_ctx_switch )
 +      {
 +              sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
 +              sstrncpy (vl.type_instance, "voluntary", sizeof (vl.type_instance));
 +              vl.values[0].derive = ps->cswitch_vol;
 +              vl.values_len = 1;
 +              plugin_dispatch_values (&vl);
 +
 +              sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
 +              sstrncpy (vl.type_instance, "involuntary", sizeof (vl.type_instance));
 +              vl.values[0].derive = ps->cswitch_invol;
 +              vl.values_len = 1;
 +              plugin_dispatch_values (&vl);
 +      }
 +
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
                        "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
                        "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
                        "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
                        "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; "
 -                      "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";",
 +                      "io_syscr = %"PRIi64"; io_syscw = %"PRIi64"; "
 +                      "cswitch_vol = %"PRIi64"; cswitch_invol = %"PRIi64";",
                        ps->name, ps->num_proc, ps->num_lwp,
                        ps->vmem_size, ps->vmem_rss,
                        ps->vmem_data, ps->vmem_code,
                        ps->vmem_minflt_counter, ps->vmem_majflt_counter,
                        ps->cpu_user_counter, ps->cpu_system_counter,
 -                      ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw);
 +                      ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw,
 +                      ps->cswitch_vol, ps->cswitch_invol);
  } /* void ps_submit_proc_list */
  
  #if KERNEL_LINUX || KERNEL_SOLARIS
@@@ -815,99 -775,42 +815,99 @@@ static void ps_submit_fork_rate (derive
  
  /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
  #if KERNEL_LINUX
 -static int ps_read_tasks (int pid)
 +static procstat_t *ps_read_tasks_status (int pid, procstat_t *ps)
  {
        char           dirname[64];
        DIR           *dh;
 +      char           filename[64];
 +      FILE          *fh;
        struct dirent *ent;
 -      int count = 0;
 +      derive_t cswitch_vol = 0;
 +      derive_t cswitch_invol = 0;
 +      char buffer[1024];
 +      char *fields[8];
 +      int numfields;
  
        ssnprintf (dirname, sizeof (dirname), "/proc/%i/task", pid);
  
        if ((dh = opendir (dirname)) == NULL)
        {
                DEBUG ("Failed to open directory `%s'", dirname);
 -              return (-1);
 +              return (NULL);
        }
  
        while ((ent = readdir (dh)) != NULL)
        {
 +              char *tpid;
 +
                if (!isdigit ((int) ent->d_name[0]))
                        continue;
 -              else
 -                      count++;
 +
 +              tpid = ent->d_name;
 +
 +              ssnprintf (filename, sizeof (filename), "/proc/%i/task/%s/status", pid, tpid);
 +              if ((fh = fopen (filename, "r")) == NULL)
 +              {
 +                      DEBUG ("Failed to open file `%s'", filename);
 +                      continue;
 +              }
 +
 +              while (fgets (buffer, sizeof(buffer), fh) != NULL)
 +              {
 +                      derive_t tmp;
 +                      char *endptr;
 +
 +                      if (strncmp (buffer, "voluntary_ctxt_switches", 23) != 0
 +                              && strncmp (buffer, "nonvoluntary_ctxt_switches", 26) != 0)
 +                              continue;
 +
 +                      numfields = strsplit (buffer, fields,
 +                              STATIC_ARRAY_SIZE (fields));
 +
 +                      if (numfields < 2)
 +                              continue;
 +
 +                      errno = 0;
 +                      endptr = NULL;
 +                      tmp = (derive_t) strtoll (fields[1], &endptr, /* base = */ 10);
 +                      if ((errno == 0) && (endptr != fields[1]))
 +                      {
 +                              if (strncmp (buffer, "voluntary_ctxt_switches", 23) == 0)
 +                              {
 +                                      cswitch_vol += tmp;
 +                              }
 +                              else if (strncmp (buffer, "nonvoluntary_ctxt_switches", 26) == 0)
 +                              {
 +                                      cswitch_invol += tmp;
 +                              }
 +                      }
 +              } /* while (fgets) */
 +
 +              if (fclose (fh))
 +              {
 +                      char errbuf[1024];
 +                              WARNING ("processes: fclose: %s",
 +                                      sstrerror (errno, errbuf, sizeof (errbuf)));
 +              }
        }
        closedir (dh);
  
 -      return ((count >= 1) ? count : 1);
 -} /* int *ps_read_tasks */
 +      ps->cswitch_vol = cswitch_vol;
 +      ps->cswitch_invol = cswitch_invol;
 +
 +      return (ps);
 +} /* int *ps_read_tasks_status */
  
 -/* Read advanced virtual memory data from /proc/pid/status */
 -static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
 +/* Read data from /proc/pid/status */
 +static procstat_t *ps_read_status (int pid, procstat_t *ps)
  {
        FILE *fh;
        char buffer[1024];
        char filename[64];
 -      unsigned long long lib = 0;
 -      unsigned long long exe = 0;
 -      unsigned long long data = 0;
 +      unsigned long lib = 0;
 +      unsigned long exe = 0;
 +      unsigned long data = 0;
 +      unsigned long threads = 0;
        char *fields[8];
        int numfields;
  
  
        while (fgets (buffer, sizeof(buffer), fh) != NULL)
        {
 -              long long tmp;
 +              unsigned long tmp;
                char *endptr;
  
 -              if (strncmp (buffer, "Vm", 2) != 0)
 +              if (strncmp (buffer, "Vm", 2) != 0
 +                              && strncmp (buffer, "Threads", 7) != 0)
                        continue;
  
                numfields = strsplit (buffer, fields,
  
                errno = 0;
                endptr = NULL;
 -              tmp = strtoll (fields[1], &endptr, /* base = */ 10);
 +              tmp = strtoul (fields[1], &endptr, /* base = */ 10);
                if ((errno == 0) && (endptr != fields[1]))
                {
                        if (strncmp (buffer, "VmData", 6) == 0)
                        {
                                exe = tmp;
                        }
 +                      else if  (strncmp(buffer, "Threads", 7) == 0)
 +                      {
 +                              threads = tmp;
 +                      }
                }
        } /* while (fgets) */
  
  
        ps->vmem_data = data * 1024;
        ps->vmem_code = (exe + lib) * 1024;
 +      if (threads != 0)
 +              ps->num_lwp = threads;
  
        return (ps);
  } /* procstat_t *ps_read_vmem */
@@@ -1032,9 -928,9 +1032,9 @@@ int ps_read_process (int pid, procstat_
        char *fields[64];
        char  fields_len;
  
 -      int   buffer_len;
 +      size_t buffer_len;
  
 -      char *buffer_ptr;
 +      char  *buffer_ptr;
        size_t name_start_pos;
        size_t name_end_pos;
        size_t name_len;
        long long unsigned vmem_rss;
        long long unsigned stack_size;
  
 +      ssize_t status;
 +
        memset (ps, 0, sizeof (procstat_t));
  
        ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
  
 -      buffer_len = read_file_contents (filename,
 -                      buffer, sizeof(buffer) - 1);
 -      if (buffer_len <= 0)
 +      status = read_file_contents (filename, buffer, sizeof(buffer) - 1);
 +      if (status <= 0)
                return (-1);
 +      buffer_len = (size_t) status;
        buffer[buffer_len] = 0;
  
        /* The name of the process is enclosed in parens. Since the name can
        }
        else
        {
 -              if ( (ps->num_lwp = ps_read_tasks (pid)) == -1 )
 +              ps->num_lwp = strtoul (fields[17], /* endptr = */ NULL, /* base = */ 10);
 +              if ((ps_read_status(pid, ps)) == NULL)
                {
 -                      /* returns -1 => kernel 2.4 */
 -                      ps->num_lwp = 1;
 +                      /* No VMem data */
 +                      ps->vmem_data = -1;
 +                      ps->vmem_code = -1;
 +                      DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
                }
 +              if (ps->num_lwp <= 0)
 +                      ps->num_lwp = 1;
                ps->num_proc = 1;
        }
  
        /* Leave the rest at zero if this is only a zombi */
        if (ps->num_proc == 0)
        {
-               DEBUG ("processes plugin: This is only a zombi: pid = %i; "
+               DEBUG ("processes plugin: This is only a zombie: pid = %i; "
                                "name = %s;", pid, ps->name);
                return (0);
        }
        cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
        vmem_rss = vmem_rss * pagesize_g;
  
 -      if ( (ps_read_vmem(pid, ps)) == NULL)
 -      {
 -              /* No VMem data */
 -              ps->vmem_data = -1;
 -              ps->vmem_code = -1;
 -              DEBUG("ps_read_process: did not get vmem data for pid %i",pid);
 -      }
 -
        ps->cpu_user_counter = cpu_user_counter;
        ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
                DEBUG("ps_read_process: not get io data for pid %i",pid);
        }
  
 +      if ( report_ctx_switch )
 +      {
 +              if ( (ps_read_tasks_status(pid, ps)) == NULL)
 +              {
 +                      ps->cswitch_vol = -1;
 +                      ps->cswitch_invol = -1;
 +
 +                      DEBUG("ps_read_tasks_status: not get context "
 +                                      "switch data for pid %i",pid);
 +              }
 +      }
 +
        /* success */
        return (0);
  } /* int ps_read_process (...) */
@@@ -1331,16 -1216,16 +1331,16 @@@ static const char *ps_get_cmdline (lon
  {
        char path[PATH_MAX];
        psinfo_t info;
 -      int status;
 +      ssize_t status;
  
        snprintf(path, sizeof (path), "/proc/%li/psinfo", pid);
  
        status = read_file_contents (path, (void *) &info, sizeof (info));
 -      if (status != sizeof (info))
 +      if ((status < 0) || (((size_t) status) != sizeof (info)))
        {
                ERROR ("processes plugin: Unexpected return value "
                                "while reading \"%s\": "
 -                              "Returned %i but expected %zu.",
 +                              "Returned %zd but expected %zu.",
                                path, status, buffer_size);
                return (NULL);
        }
@@@ -1437,12 -1322,6 +1437,12 @@@ static int ps_read_process(long pid, pr
        ps->io_syscr = myUsage->pr_sysc;
        ps->io_syscw = myUsage->pr_sysc;
  
 +      /*
 +       * TODO: context switch counters for Solaris
 +   */
 +      ps->cswitch_vol   = -1;
 +      ps->cswitch_invol = -1;
 +
  
        /*
         * TODO: Find way of setting BLOCKED and PAGING status
@@@ -1680,10 -1559,6 +1680,10 @@@ static int ps_read (void
  
                                pse.cpu_user_counter = task_absolutetime_info.total_user;
                                pse.cpu_system_counter = task_absolutetime_info.total_system;
 +
 +                              /* context switch counters not implemented */
 +                              pse.cswitch_vol   = -1;
 +                              pse.cswitch_invol = -1;
                        }
  
                        status = task_threads (task_list[task], &thread_list,
        DIR           *proc;
        int            pid;
  
 -      char cmdline[ARG_MAX];
 +      char cmdline[CMDLINE_BUFFER_SIZE];
  
        int        status;
        procstat_t ps;
                        continue;
                }
  
 +              memset (&pse, 0, sizeof (pse));
                pse.id       = pid;
                pse.age      = 0;
  
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
  
 +              pse.cswitch_vol = ps.cswitch_vol;
 +              pse.cswitch_invol = ps.cswitch_invol;
 +
                switch (state)
                {
                        case 'R': running++;  break;
                 * filter out threads (duplicate PID entries). */
                if ((proc_ptr == NULL) || (proc_ptr->ki_pid != procs[i].ki_pid))
                {
 -                      char cmdline[ARG_MAX] = "";
 +                      char cmdline[CMDLINE_BUFFER_SIZE] = "";
                        _Bool have_cmdline = 0;
  
                        proc_ptr = &(procs[i]);
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 +                      /* context switch counters not implemented */
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
                        ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse);
  
                        switch (procs[i].ki_stat)
                ps_submit_proc_list (ps_ptr);
  /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
  
 +#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD
 +      int running  = 0;
 +      int sleeping = 0;
 +      int zombies  = 0;
 +      int stopped  = 0;
 +      int onproc   = 0;
 +      int idle     = 0;
 +      int dead     = 0;
 +
 +      kvm_t *kd;
 +      char errbuf[1024];
 +      struct kinfo_proc *procs;          /* array of processes */
 +      struct kinfo_proc *proc_ptr = NULL;
 +      int count;                         /* returns number of processes */
 +      int i;
 +
 +      procstat_t *ps_ptr;
 +      procstat_entry_t pse;
 +
 +      ps_list_reset ();
 +
 +      /* Open the kvm interface, get a descriptor */
 +      kd = kvm_open (NULL, NULL, NULL, 0, errbuf);
 +      if (kd == NULL)
 +      {
 +              ERROR ("processes plugin: Cannot open kvm interface: %s",
 +                              errbuf);
 +              return (0);
 +      }
 +
 +      /* Get the list of processes. */
 +      procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
 +      if (procs == NULL)
 +      {
 +              ERROR ("processes plugin: Cannot get kvm processes list: %s",
 +                              kvm_geterr(kd));
 +              kvm_close (kd);
 +              return (0);
 +      }
 +
 +      /* Iterate through the processes in kinfo_proc */
 +      for (i = 0; i < count; i++)
 +      {
 +              /* Create only one process list entry per _process_, i.e.
 +               * filter out threads (duplicate PID entries). */
 +              if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid))
 +              {
 +                      char cmdline[CMDLINE_BUFFER_SIZE] = "";
 +                      _Bool have_cmdline = 0;
 +
 +                      proc_ptr = &(procs[i]);
 +                      /* Don't probe zombie processes  */
 +                      if (!P_ZOMBIE(proc_ptr))
 +                      {
 +                              char **argv;
 +                              int argc;
 +                              int status;
 +
 +                              /* retrieve the arguments */
 +                              argv = kvm_getargv (kd, proc_ptr, /* nchr = */ 0);
 +                              argc = 0;
 +                              if ((argv != NULL) && (argv[0] != NULL))
 +                              {
 +                                      while (argv[argc] != NULL)
 +                                              argc++;
 +
 +                                      status = strjoin (cmdline, sizeof (cmdline), argv, argc, " ");
 +                                      if (status < 0)
 +                                              WARNING ("processes plugin: Command line did not fit into buffer.");
 +                                      else
 +                                              have_cmdline = 1;
 +                              }
 +                      } /* if (process has argument list) */
 +
 +                      memset (&pse, 0, sizeof (pse));
 +                      pse.id       = procs[i].p_pid;
 +                      pse.age      = 0;
 +
 +                      pse.num_proc = 1;
 +                      pse.num_lwp  = 1; /* XXX: accumulate p_tid values for a single p_pid ? */
 +
 +                      pse.vmem_rss = procs[i].p_vm_rssize * pagesize;
 +                      pse.vmem_data = procs[i].p_vm_dsize * pagesize;
 +                      pse.vmem_code = procs[i].p_vm_tsize * pagesize;
 +                      pse.stack_size = procs[i].p_vm_ssize * pagesize;
 +                      pse.vmem_size = pse.stack_size + pse.vmem_code + pse.vmem_data;
 +                      pse.vmem_minflt = 0;
 +                      pse.vmem_minflt_counter = procs[i].p_uru_minflt;
 +                      pse.vmem_majflt = 0;
 +                      pse.vmem_majflt_counter = procs[i].p_uru_majflt;
 +
 +                      pse.cpu_user = 0;
 +                      pse.cpu_system = 0;
 +                      pse.cpu_user_counter = procs[i].p_uutime_usec +
 +                                              (1000000lu * procs[i].p_uutime_sec);
 +                      pse.cpu_system_counter = procs[i].p_ustime_usec +
 +                                              (1000000lu * procs[i].p_ustime_sec);
 +
 +                      /* no I/O data */
 +                      pse.io_rchar = -1;
 +                      pse.io_wchar = -1;
 +                      pse.io_syscr = -1;
 +                      pse.io_syscw = -1;
 +
 +                      /* context switch counters not implemented */
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
 +                      ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
 +
 +                      switch (procs[i].p_stat)
 +                      {
 +                              case SSTOP:     stopped++;      break;
 +                              case SSLEEP:    sleeping++;     break;
 +                              case SRUN:      running++;      break;
 +                              case SIDL:      idle++;         break;
 +                              case SONPROC:   onproc++;       break;
 +                              case SDEAD:     dead++;         break;
 +                              case SZOMB:     zombies++;      break;
 +                      }
 +              } /* if ((proc_ptr == NULL) || (proc_ptr->p_pid != procs[i].p_pid)) */
 +      }
 +
 +      kvm_close(kd);
 +
 +      ps_submit_state ("running",  running);
 +      ps_submit_state ("sleeping", sleeping);
 +      ps_submit_state ("zombies",  zombies);
 +      ps_submit_state ("stopped",  stopped);
 +      ps_submit_state ("onproc",   onproc);
 +      ps_submit_state ("idle",     idle);
 +      ps_submit_state ("dead",     dead);
 +
 +      for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
 +              ps_submit_proc_list (ps_ptr);
 +/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD */
 +
  #elif HAVE_PROCINFO_H
        /* AIX */
        int running  = 0;
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
                        ps_list_add (cmdline, cargs, &pse);
                } /* for (i = 0 .. nprocs) */
  
                        continue;
                }
  
 +              memset (&pse, 0, sizeof (pse));
                pse.id = pid;
                pse.age = 0;
  
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
  
 +              pse.cswitch_vol = -1;
 +              pse.cswitch_invol = -1;
 +
                switch (state)
                {
                        case 'R': running++;  break;