Merge branch 'collectd-5.5'
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Fri, 4 Mar 2016 11:19:47 +0000 (12:19 +0100)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Fri, 4 Mar 2016 11:19:47 +0000 (12:19 +0100)
1  2 
src/ceph.c
src/daemon/plugin.c
src/processes.c
src/python.c

diff --combined src/ceph.c
@@@ -45,6 -45,7 +45,6 @@@
  #include <stdlib.h>
  #include <string.h>
  #include <strings.h>
 -#include <sys/socket.h>
  #include <sys/time.h>
  #include <sys/types.h>
  #include <sys/un.h>
@@@ -1096,7 -1097,7 +1096,7 @@@ static int cconn_connect(struct cconn *
      fd = socket(PF_UNIX, SOCK_STREAM, 0);
      if(fd < 0)
      {
-         int err = -errno;
+         err = -errno;
          ERROR("ceph plugin: cconn_connect: socket(PF_UNIX, SOCK_STREAM, 0) "
              "failed: error %d", err);
          return err;
@@@ -1545,7 -1546,7 +1545,7 @@@ static int cconn_main_loop(uint32_t req
              }
              else
              {
-                 int ret = cconn_handle_event(io);
+                 ret = cconn_handle_event(io);
                  if(ret)
                  {
                      WARNING("ceph plugin: cconn_handle_event(name=%s,"
diff --combined src/daemon/plugin.c
@@@ -80,12 -80,6 +80,12 @@@ struct write_queue_
        write_queue_t *next;
  };
  
 +struct flush_callback_s {
 +      char *name;
 +      cdtime_t timeout;
 +};
 +typedef struct flush_callback_s flush_callback_t;
 +
  /*
   * Private variables
   */
@@@ -288,7 -282,7 +288,7 @@@ static int register_callback (llist_t *
                {
                        ERROR ("plugin: register_callback: "
                                        "llentry_create failed.");
 -                      free (key);
 +                      sfree (key);
                        destroy_callback (cf);
                        return (-1);
                }
@@@ -358,9 -352,9 +358,9 @@@ static void log_list_callbacks (llist_
                *str = '\0';
                strjoin(str, len, keys, n, "', '");
                INFO("%s ['%s']", comment, str);
 -              free(str);
 +              sfree (str);
        }
 -      free(keys);
 +      sfree (keys);
  } /* }}} void log_list_callbacks */
  
  static int create_register_callback (llist_t **list, /* {{{ */
@@@ -483,9 -477,7 +483,9 @@@ static void *plugin_read_thread (void _
        {
                read_func_t *rf;
                plugin_ctx_t old_ctx;
 +              cdtime_t start;
                cdtime_t now;
 +              cdtime_t elapsed;
                int status;
                int rf_type;
                int rc;
  
                DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name);
  
 +              start = cdtime ();
 +
                old_ctx = plugin_set_ctx (rf->rf_ctx);
  
                if (rf_type == RF_SIMPLE)
                /* update the ``next read due'' field */
                now = cdtime ();
  
 +              /* calculate the time spent in the read function */
 +              elapsed = (now - start);
 +
 +              if (elapsed > rf->rf_effective_interval)
 +                      WARNING ("plugin_read_thread: read-function of the `%s' plugin took %.3f "
 +                              "seconds, which is above its read interval (%.3f seconds). You might "
 +                              "want to adjust the `Interval' or `ReadThreads' settings.",
 +                              rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed),
 +                              CDTIME_T_TO_DOUBLE(rf->rf_effective_interval));
 +
 +              DEBUG ("plugin_read_thread: read-function of the `%s' plugin took "
 +                              "%.6f seconds.",
 +                              rf->rf_name, CDTIME_T_TO_DOUBLE(elapsed));
 +
                DEBUG ("plugin_read_thread: Effective interval of the "
 -                              "%s plugin is %.3f seconds.",
 +                              "`%s' plugin is %.3f seconds.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_effective_interval));
  
                        rf->rf_next_read = now;
                }
  
 -              DEBUG ("plugin_read_thread: Next read of the %s plugin at %.3f.",
 +              DEBUG ("plugin_read_thread: Next read of the `%s' plugin at %.3f.",
                                rf->rf_name,
                                CDTIME_T_TO_DOUBLE (rf->rf_next_read));
  
@@@ -907,7 -883,7 +907,7 @@@ static void start_write_threads (size_
  static void stop_write_threads (void) /* {{{ */
  {
        write_queue_t *q;
 -      int i;
 +      size_t i;
  
        if (write_threads == NULL)
                return;
  
        if (i > 0)
        {
 -              WARNING ("plugin: %i value list%s left after shutting down "
 +              WARNING ("plugin: %zu value list%s left after shutting down "
                                "the write threads.",
                                i, (i == 1) ? " was" : "s were");
        }
   */
  void plugin_set_dir (const char *dir)
  {
 -      if (plugindir != NULL)
 -              free (plugindir);
 +      sfree (plugindir);
  
        if (dir == NULL)
 -              plugindir = NULL;
 -      else if ((plugindir = strdup (dir)) == NULL)
        {
 -              char errbuf[1024];
 -              ERROR ("strdup failed: %s",
 -                              sstrerror (errno, errbuf, sizeof (errbuf)));
 +              plugindir = NULL;
 +              return;
        }
 +
 +      plugindir = strdup (dir);
 +      if (plugindir == NULL)
 +              ERROR ("plugin_set_dir: strdup(\"%s\") failed", dir);
  }
  
  static _Bool plugin_is_loaded (char const *name)
@@@ -998,7 -974,7 +998,7 @@@ static int plugin_mark_loaded (char con
        return (status);
  }
  
- static void plugin_free_loaded ()
+ static void plugin_free_loaded (void)
  {
        void *key;
        void *value;
@@@ -1107,7 -1083,6 +1107,7 @@@ int plugin_load (char const *plugin_nam
                        /* success */
                        plugin_mark_loaded (plugin_name);
                        ret = 0;
 +                      INFO ("plugin_load: plugin \"%s\" successfully loaded.", plugin_name);
                        break;
                }
                else
@@@ -1272,7 -1247,7 +1272,7 @@@ int plugin_register_read (const char *n
  
  int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
 -              const struct timespec *interval,
 +              cdtime_t interval,
                user_data_t *user_data)
  {
        read_func_t *rf;
                rf->rf_group[0] = '\0';
        rf->rf_name = strdup (name);
        rf->rf_type = RF_COMPLEX;
 -      if (interval != NULL)
 -              rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
 -      else
 -              rf->rf_interval = plugin_get_interval ();
 +      rf->rf_interval = (interval != 0) ? interval : plugin_get_interval ();
  
        /* Set user data */
        if (user_data == NULL)
@@@ -1324,105 -1302,11 +1324,105 @@@ int plugin_register_write (const char *
                                (void *) callback, ud));
  } /* int plugin_register_write */
  
 +static int plugin_flush_timeout_callback (user_data_t *ud)
 +{
 +      flush_callback_t *cb = ud->data;
 +
 +      return plugin_flush (cb->name, cb->timeout, /* identifier = */ NULL);
 +} /* static int plugin_flush_callback */
 +
 +static void plugin_flush_timeout_callback_free (void *data)
 +{
 +      flush_callback_t *cb = data;
 +
 +      if (cb == NULL) return;
 +
 +      sfree (cb->name);
 +      sfree (cb);
 +} /* static void plugin_flush_callback_free */
 +
 +static char *plugin_flush_callback_name (const char *name)
 +{
 +      char *flush_prefix = "flush/";
 +      size_t prefix_size;
 +      char *flush_name;
 +      size_t name_size;
 +
 +      prefix_size = strlen(flush_prefix);
 +      name_size = strlen(name);
 +
 +      flush_name = malloc (sizeof(char) * (name_size + prefix_size + 1));
 +      if (flush_name == NULL)
 +      {
 +              ERROR ("plugin_flush_callback_name: malloc failed.");
 +              return (NULL);
 +      }
 +
 +      sstrncpy (flush_name, flush_prefix, prefix_size + 1);
 +      sstrncpy (flush_name + prefix_size, name, name_size + 1);
 +
 +      return flush_name;
 +} /* static char *plugin_flush_callback_name */
 +
  int plugin_register_flush (const char *name,
                plugin_flush_cb callback, user_data_t *ud)
  {
 -      return (create_register_callback (&list_flush, name,
 -                              (void *) callback, ud));
 +      int status;
 +      plugin_ctx_t ctx = plugin_get_ctx ();
 +
 +      status = create_register_callback (&list_flush, name,
 +              (void *) callback, ud);
 +      if (status != 0)
 +              return status;
 +
 +      if (ctx.flush_interval != 0)
 +      {
 +              char *flush_name;
 +              user_data_t ud;
 +              flush_callback_t *cb;
 +
 +              flush_name = plugin_flush_callback_name (name);
 +              if (flush_name == NULL)
 +                      return (-1);
 +
 +              cb = malloc(sizeof(flush_callback_t));
 +              if (cb == NULL)
 +              {
 +                      ERROR ("plugin_register_flush: malloc failed.");
 +                      sfree (flush_name);
 +                      return (-1);
 +              }
 +
 +              cb->name = strdup (name);
 +              if (cb->name == NULL)
 +              {
 +                      ERROR ("plugin_register_flush: strdup failed.");
 +                      sfree (cb);
 +                      sfree (flush_name);
 +                      return (-1);
 +              }
 +              cb->timeout = ctx.flush_timeout;
 +
 +              ud.data = cb;
 +              ud.free_func = plugin_flush_timeout_callback_free;
 +
 +              status = plugin_register_complex_read (
 +                      /* group     = */ "flush",
 +                      /* name      = */ flush_name,
 +                      /* callback  = */ plugin_flush_timeout_callback,
 +                      /* interval  = */ ctx.flush_interval,
 +                      /* user data = */ &ud);
 +
 +              sfree (flush_name);
 +              if (status != 0)
 +              {
 +                      sfree (cb->name);
 +                      sfree (cb);
 +                      return status;
 +              }
 +      }
 +
 +      return 0;
  } /* int plugin_register_flush */
  
  int plugin_register_missing (const char *name,
@@@ -1463,7 -1347,7 +1463,7 @@@ static void plugin_free_data_sets (void
  int plugin_register_data_set (const data_set_t *ds)
  {
        data_set_t *ds_copy;
 -      int i;
 +      size_t i;
  
        if ((data_sets != NULL)
                        && (c_avl_get (data_sets, ds->type, NULL) == 0))
                        * ds->ds_num);
        if (ds_copy->ds == NULL)
        {
 -              free (ds_copy);
 +              sfree (ds_copy);
                return (-1);
        }
  
@@@ -1641,21 -1525,7 +1641,21 @@@ int plugin_unregister_write (const cha
  
  int plugin_unregister_flush (const char *name)
  {
 -      return (plugin_unregister (list_flush, name));
 +      plugin_ctx_t ctx = plugin_get_ctx ();
 +
 +      if (ctx.flush_interval != 0)
 +      {
 +              char *flush_name;
 +
 +              flush_name = plugin_flush_callback_name (name);
 +              if (flush_name != NULL)
 +              {
 +                      plugin_unregister_read(flush_name);
 +                      sfree (flush_name);
 +              }
 +      }
 +
 +      return plugin_unregister (list_flush, name);
  }
  
  int plugin_unregister_missing (const char *name)
@@@ -2160,8 -2030,8 +2160,8 @@@ static int plugin_dispatch_values_inter
        if (ds->ds_num != vl->values_len)
        {
                ERROR ("plugin_dispatch_values: ds->type = %s: "
 -                              "(ds->ds_num = %i) != "
 -                              "(vl->values_len = %i)",
 +                              "(ds->ds_num = %zu) != "
 +                              "(vl->values_len = %zu)",
                                ds->type, ds->ds_num, vl->values_len);
                return (-1);
        }
                         * don't get confused.. */
                        if (saved_values != NULL)
                        {
 -                              free (vl->values);
 +                              sfree (vl->values);
                                vl->values     = saved_values;
                                vl->values_len = saved_values_len;
                        }
         * confused.. */
        if (saved_values != NULL)
        {
 -              free (vl->values);
 +              sfree (vl->values);
                vl->values     = saved_values;
                vl->values_len = saved_values_len;
        }
@@@ -2729,11 -2599,7 +2729,11 @@@ int plugin_notification_meta_free (noti
  
      if (this->type == NM_TYPE_STRING)
      {
 -      free ((char *)this->nm_value.nm_string);
 +      /* Assign to a temporary variable to work around nm_string's const
 +       * modifier. */
 +      void *tmp = (void *) this->nm_value.nm_string;
 +
 +      sfree (tmp);
        this->nm_value.nm_string = NULL;
      }
      sfree (this);
@@@ -2840,7 -2706,7 +2840,7 @@@ static void *plugin_thread_start (void 
  
        plugin_set_ctx (plugin_thread->ctx);
  
 -      free (plugin_thread);
 +      sfree (plugin_thread);
  
        return start_routine (plugin_arg);
  } /* void *plugin_thread_start */
diff --combined src/processes.c
@@@ -180,9 -180,6 +180,9 @@@ typedef struct procstat_entry_
        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 -211,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;
@@@ -287,8 -279,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;
                }
        }
@@@ -361,31 -353,6 +361,31 @@@ static int ps_list_match (const char *n
        return (0);
  } /* int ps_list_match */
  
 +static void ps_update_counter (
 +        _Bool init,
 +        derive_t *group_counter,
 +        derive_t *curr_counter, unsigned long *curr_value,
 +        derive_t new_counter, unsigned long new_value) {
 +    if (init)
 +    {
 +        *curr_value = new_value;
 +        *curr_counter += new_value;
 +        *group_counter += new_value;
 +        return;
 +    }
 +
 +    if (new_counter < *curr_counter)
 +    {
 +        *curr_value = new_counter + (ULONG_MAX - *curr_counter);
 +    }
 +    else
 +    {
 +        *curr_value = new_counter - *curr_counter;
 +    }
 +    *curr_counter = new_counter;
 +    *group_counter += *curr_value;
 +}
 +
  /* add process entry to 'instances' of process 'name' (or refresh it) */
  static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t *entry)
  {
  
        for (ps = list_head_g; ps != NULL; ps = ps->next)
        {
 +        _Bool want_init;
 +
                if ((ps_list_match (name, cmdline, ps)) == 0)
                        continue;
  
                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);
  
 -              if ((entry->vmem_minflt_counter == 0)
 -                              && (entry->vmem_majflt_counter == 0))
 -              {
 -                      pse->vmem_minflt_counter += entry->vmem_minflt;
 -                      pse->vmem_minflt = entry->vmem_minflt;
 -
 -                      pse->vmem_majflt_counter += entry->vmem_majflt;
 -                      pse->vmem_majflt = entry->vmem_majflt;
 -              }
 -              else
 -              {
 -                      if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
 -                      {
 -                              pse->vmem_minflt = entry->vmem_minflt_counter
 -                                      + (ULONG_MAX - pse->vmem_minflt_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
 -                      }
 -                      pse->vmem_minflt_counter = entry->vmem_minflt_counter;
 -
 -                      if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
 -                      {
 -                              pse->vmem_majflt = entry->vmem_majflt_counter
 -                                      + (ULONG_MAX - pse->vmem_majflt_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
 -                      }
 -                      pse->vmem_majflt_counter = entry->vmem_majflt_counter;
 -              }
 -
 -              ps->vmem_minflt_counter += pse->vmem_minflt;
 -              ps->vmem_majflt_counter += pse->vmem_majflt;
 -
 -              if ((entry->cpu_user_counter == 0)
 -                              && (entry->cpu_system_counter == 0))
 -              {
 -                      pse->cpu_user_counter += entry->cpu_user;
 -                      pse->cpu_user = entry->cpu_user;
 -
 -                      pse->cpu_system_counter += entry->cpu_system;
 -                      pse->cpu_system = entry->cpu_system;
 -              }
 -              else
 -              {
 -                      if (entry->cpu_user_counter < pse->cpu_user_counter)
 -                      {
 -                              pse->cpu_user = entry->cpu_user_counter
 -                                      + (ULONG_MAX - pse->cpu_user_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
 -                      }
 -                      pse->cpu_user_counter = entry->cpu_user_counter;
 -
 -                      if (entry->cpu_system_counter < pse->cpu_system_counter)
 -                      {
 -                              pse->cpu_system = entry->cpu_system_counter
 -                                      + (ULONG_MAX - pse->cpu_system_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
 -                      }
 -                      pse->cpu_system_counter = entry->cpu_system_counter;
 -              }
 -
 -              ps->cpu_user_counter   += pse->cpu_user;
 -              ps->cpu_system_counter += pse->cpu_system;
 +              ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
 +              ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
 +
 +              want_init = (entry->vmem_minflt_counter == 0)
 +                              && (entry->vmem_majflt_counter == 0);
 +              ps_update_counter (want_init,
 +                              &ps->vmem_minflt_counter,
 +                              &pse->vmem_minflt_counter, &pse->vmem_minflt,
 +                              entry->vmem_minflt_counter, entry->vmem_minflt);
 +              ps_update_counter (want_init,
 +                              &ps->vmem_majflt_counter,
 +                              &pse->vmem_majflt_counter, &pse->vmem_majflt,
 +                              entry->vmem_majflt_counter, entry->vmem_majflt);
 +
 +              want_init = (entry->cpu_user_counter == 0)
 +                              && (entry->cpu_system_counter == 0);
 +              ps_update_counter (want_init,
 +                              &ps->cpu_user_counter,
 +                              &pse->cpu_user_counter, &pse->cpu_user,
 +                              entry->cpu_user_counter, entry->cpu_user);
 +              ps_update_counter (want_init,
 +                              &ps->cpu_system_counter,
 +                              &pse->cpu_system_counter, &pse->cpu_system,
 +                              entry->cpu_system_counter, entry->cpu_system);
        }
  }
  
@@@ -499,8 -511,6 +499,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;
@@@ -585,10 -595,6 +585,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 "
@@@ -738,36 -744,19 +738,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
@@@ -792,99 -781,42 +792,99 @@@ static void ps_submit_fork_rate (derive
  
  /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
  #if KERNEL_LINUX
 -static int ps_read_tasks (long pid)
 +static procstat_t *ps_read_tasks_status (long 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/%li/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/%li/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 (long pid, procstat_t *ps)
 +/* Read data from /proc/pid/status */
 +static procstat_t *ps_read_status (long 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 */
@@@ -1009,9 -934,9 +1009,9 @@@ static int ps_read_process (long pid, p
        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/%li/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 %li", pid);
                }
 +              if (ps->num_lwp <= 0)
 +                      ps->num_lwp = 1;
                ps->num_proc = 1;
        }
  
        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 %li", 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 %li", 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 %li", pid);
 +              }
 +      }
 +
        /* success */
        return (0);
  } /* int ps_read_process (...) */
@@@ -1255,7 -1169,7 +1255,7 @@@ static char *ps_get_cmdline (long pid, 
        return buf;
  } /* char *ps_get_cmdline (...) */
  
- static int read_fork_rate ()
+ static int read_fork_rate (void)
  {
        FILE *proc_stat;
        char buffer[1024];
@@@ -1307,16 -1221,16 +1307,16 @@@ static char *ps_get_cmdline (long pid, 
  {
        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);
        }
@@@ -1413,12 -1327,6 +1413,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
@@@ -1656,10 -1564,6 +1656,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,
                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;
                        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)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 -                      pse.cswitch_vol = -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);
                        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) */
  
diff --combined src/python.c
@@@ -355,7 -355,7 +355,7 @@@ static int cpy_read_callback(user_data_
  }
  
  static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_list, user_data_t *data) {
 -      int i;
 +      size_t i;
        cpy_callback_t *c = data->data;
        PyObject *ret, *list, *temp, *dict = NULL;
        Values *v;
                }
                for (i = 0; i < value_list->values_len; ++i) {
                        if (ds->ds[i].type == DS_TYPE_COUNTER) {
 -                              if ((long) value_list->values[i].counter == value_list->values[i].counter)
 -                                      PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].counter));
 -                              else
 -                                      PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
 +                              PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].counter));
                        } else if (ds->ds[i].type == DS_TYPE_GAUGE) {
                                PyList_SetItem(list, i, PyFloat_FromDouble(value_list->values[i].gauge));
                        } else if (ds->ds[i].type == DS_TYPE_DERIVE) {
 -                              if ((long) value_list->values[i].derive == value_list->values[i].derive)
 -                                      PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].derive));
 -                              else
 -                                      PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
 +                              PyList_SetItem(list, i, PyLong_FromLongLong(value_list->values[i].derive));
                        } else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) {
 -                              if ((long) value_list->values[i].absolute == value_list->values[i].absolute)
 -                                      PyList_SetItem(list, i, PyInt_FromLong(value_list->values[i].absolute));
 -                              else
 -                                      PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
 +                              PyList_SetItem(list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
                        } else {
                                Py_BEGIN_ALLOW_THREADS
                                ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
@@@ -575,7 -584,7 +575,7 @@@ static PyObject *float_or_none(float nu
  }
  
  static PyObject *cpy_get_dataset(PyObject *self, PyObject *args) {
 -      int i;
 +      size_t i;
        char *name;
        const data_set_t *ds;
        PyObject *list, *tuple;
@@@ -669,6 -678,7 +669,6 @@@ static PyObject *cpy_register_read(PyOb
        double interval = 0;
        char *name = NULL;
        PyObject *callback = NULL, *data = NULL;
 -      struct timespec ts;
        static char *kwlist[] = {"callback", "interval", "data", "name", NULL};
        
        if (PyArg_ParseTupleAndKeywords(args, kwds, "O|dOet", kwlist, &callback, &interval, &data, NULL, &name) == 0) return NULL;
        user_data.free_func = cpy_destroy_user_data;
        user_data.data = c;
  
 -      ts.tv_sec = interval;
 -      ts.tv_nsec = (interval - ts.tv_sec) * 1000000000;
        plugin_register_complex_read(/* group = */ "python", buf,
 -                      cpy_read_callback, &ts, &user_data);
 -
 +                      cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), &user_data);
        return cpy_string_to_unicode_or_bytes(buf);
  }
  
@@@ -1050,7 -1063,7 +1050,7 @@@ PyMODINIT_FUNC PyInit_collectd(void) 
  }
  #endif
  
- static int cpy_init_python() {
+ static int cpy_init_python(void) {
        PyObject *sys;
        PyObject *module;