X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fdaemon%2Fplugin.c;h=c6efc3fe439b35ed396b22a391938e2af98c6e3c;hp=a8e6ca1312a61c92ff352740fe8f0873d287ecb5;hb=b847e8ff2fd928813397466a941947c8fce66d66;hpb=c2349cf65ba6ddf9517def5ab1f73706f5ce8e01 diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c index a8e6ca13..c6efc3fe 100644 --- a/src/daemon/plugin.c +++ b/src/daemon/plugin.c @@ -26,6 +26,7 @@ **/ #include "collectd.h" + #include "common.h" #include "plugin.h" #include "configfile.h" @@ -80,6 +81,12 @@ struct write_queue_s write_queue_t *next; }; +struct flush_callback_s { + char *name; + cdtime_t timeout; +}; +typedef struct flush_callback_s flush_callback_t; + /* * Private variables */ @@ -282,7 +289,7 @@ static int register_callback (llist_t **list, /* {{{ */ { ERROR ("plugin: register_callback: " "llentry_create failed."); - free (key); + sfree (key); destroy_callback (cf); return (-1); } @@ -312,8 +319,8 @@ static void log_list_callbacks (llist_t **list, /* {{{ */ { char *str; int len; - llentry_t *le; int i; + llentry_t *le; int n; char **keys; @@ -352,9 +359,9 @@ static void log_list_callbacks (llist_t **list, /* {{{ */ *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, /* {{{ */ @@ -362,13 +369,12 @@ static int create_register_callback (llist_t **list, /* {{{ */ { callback_func_t *cf; - cf = (callback_func_t *) malloc (sizeof (*cf)); + cf = calloc (1, sizeof (*cf)); if (cf == NULL) { - ERROR ("plugin: create_register_callback: malloc failed."); + ERROR ("plugin: create_register_callback: calloc failed."); return (-1); } - memset (cf, 0, sizeof (*cf)); cf->cf_callback = callback; if (ud == NULL) @@ -477,7 +483,9 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) { 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; @@ -556,6 +564,8 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) DEBUG ("plugin_read_thread: Handling `%s'.", rf->rf_name); + start = cdtime (); + old_ctx = plugin_set_ctx (rf->rf_ctx); if (rf_type == RF_SIMPLE) @@ -599,8 +609,22 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) /* 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)); @@ -617,7 +641,7 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) 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)); @@ -631,8 +655,6 @@ static void *plugin_read_thread (void __attribute__((unused)) *args) static void start_read_threads (int num) { - int i; - if (read_threads != NULL) return; @@ -644,7 +666,7 @@ static void start_read_threads (int num) } read_threads_num = 0; - for (i = 0; i < num; i++) + for (int i = 0; i < num; i++) { if (pthread_create (read_threads + read_threads_num, NULL, plugin_read_thread, NULL) == 0) @@ -661,8 +683,6 @@ static void start_read_threads (int num) static void stop_read_threads (void) { - int i; - if (read_threads == NULL) return; @@ -674,7 +694,7 @@ static void stop_read_threads (void) pthread_cond_broadcast (&read_cond); pthread_mutex_unlock (&read_lock); - for (i = 0; i < read_threads_num; i++) + for (int i = 0; i < read_threads_num; i++) { if (pthread_join (read_threads[i], NULL) != 0) { @@ -846,8 +866,6 @@ static void *plugin_write_thread (void __attribute__((unused)) *args) /* {{{ */ static void start_write_threads (size_t num) /* {{{ */ { - size_t i; - if (write_threads != NULL) return; @@ -859,7 +877,7 @@ static void start_write_threads (size_t num) /* {{{ */ } write_threads_num = 0; - for (i = 0; i < num; i++) + for (size_t i = 0; i < num; i++) { int status; @@ -883,7 +901,7 @@ static void start_write_threads (size_t num) /* {{{ */ static void stop_write_threads (void) /* {{{ */ { write_queue_t *q; - int i; + size_t i; if (write_threads == NULL) return; @@ -924,7 +942,7 @@ static void stop_write_threads (void) /* {{{ */ 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"); } @@ -935,17 +953,17 @@ static void stop_write_threads (void) /* {{{ */ */ 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) @@ -953,7 +971,7 @@ static _Bool plugin_is_loaded (char const *name) int status; if (plugins_loaded == NULL) - plugins_loaded = c_avl_create ((void *) strcasecmp); + plugins_loaded = c_avl_create ((int (*) (const void *, const void *)) strcasecmp); assert (plugins_loaded != NULL); status = c_avl_get (plugins_loaded, name, /* ret_value = */ NULL); @@ -1083,6 +1101,7 @@ int plugin_load (char const *plugin_name, uint32_t flags) /* success */ plugin_mark_loaded (plugin_name); ret = 0; + INFO ("plugin_load: plugin \"%s\" successfully loaded.", plugin_name); break; } else @@ -1219,14 +1238,13 @@ int plugin_register_read (const char *name, read_func_t *rf; int status; - rf = malloc (sizeof (*rf)); + rf = calloc (1, sizeof (*rf)); if (rf == NULL) { - ERROR ("plugin_register_read: malloc failed."); + ERROR ("plugin_register_read: calloc failed."); return (ENOMEM); } - memset (rf, 0, sizeof (read_func_t)); rf->rf_callback = (void *) callback; rf->rf_udata.data = NULL; rf->rf_udata.free_func = NULL; @@ -1247,20 +1265,19 @@ int plugin_register_read (const char *name, 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; int status; - rf = malloc (sizeof (*rf)); + rf = calloc (1,sizeof (*rf)); if (rf == NULL) { - ERROR ("plugin_register_complex_read: malloc failed."); + ERROR ("plugin_register_complex_read: calloc failed."); return (ENOMEM); } - memset (rf, 0, sizeof (read_func_t)); rf->rf_callback = (void *) callback; if (group != NULL) sstrncpy (rf->rf_group, group, sizeof (rf->rf_group)); @@ -1268,10 +1285,7 @@ int plugin_register_complex_read (const char *group, const char *name, 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) @@ -1302,11 +1316,104 @@ int plugin_register_write (const char *name, (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) +{ + const 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 (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; + flush_callback_t *cb; + + flush_name = plugin_flush_callback_name (name); + if (flush_name == NULL) + return (-1); + + cb = malloc(sizeof (*cb)); + 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, @@ -1347,7 +1454,6 @@ static void plugin_free_data_sets (void) int plugin_register_data_set (const data_set_t *ds) { data_set_t *ds_copy; - int i; if ((data_sets != NULL) && (c_avl_get (data_sets, ds->type, NULL) == 0)) @@ -1362,20 +1468,20 @@ int plugin_register_data_set (const data_set_t *ds) return (-1); } - ds_copy = (data_set_t *) malloc (sizeof (data_set_t)); + ds_copy = malloc (sizeof (*ds_copy)); if (ds_copy == NULL) return (-1); memcpy(ds_copy, ds, sizeof (data_set_t)); - ds_copy->ds = (data_source_t *) malloc (sizeof (data_source_t) + ds_copy->ds = malloc (sizeof (*ds_copy->ds) * ds->ds_num); if (ds_copy->ds == NULL) { - free (ds_copy); + sfree (ds_copy); return (-1); } - for (i = 0; i < ds->ds_num; i++) + for (size_t i = 0; i < ds->ds_num; i++) memcpy (ds_copy->ds + i, ds->ds + i, sizeof (data_source_t)); return (c_avl_insert (data_sets, (void *) ds_copy->type, (void *) ds_copy)); @@ -1525,7 +1631,21 @@ int plugin_unregister_write (const char *name) 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) @@ -1564,11 +1684,12 @@ int plugin_unregister_notification (const char *name) return (plugin_unregister (list_notification, name)); } -void plugin_init_all (void) +int plugin_init_all (void) { char const *chain_name; llentry_t *le; int status; + int ret = 0; /* Init the value cache */ uc_init (); @@ -1613,7 +1734,7 @@ void plugin_init_all (void) } if ((list_init == NULL) && (read_heap == NULL)) - return; + return ret; /* Calling all init callbacks before checking if read callbacks * are available allows the init callbacks to register the read @@ -1642,6 +1763,7 @@ void plugin_init_all (void) * handling themselves. */ /* FIXME: Unload _all_ functions */ plugin_unregister_read (le->key); + ret = -1; } le = le->next; @@ -1663,6 +1785,7 @@ void plugin_init_all (void) if (num != -1) start_read_threads ((num > 0) ? num : 5); } + return ret; } /* void plugin_init_all */ /* TODO: Rename this function. */ @@ -1846,9 +1969,10 @@ int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier) return (0); } /* int plugin_flush */ -void plugin_shutdown_all (void) +int plugin_shutdown_all (void) { llentry_t *le; + int ret = 0; // Assume success. destroy_all_callbacks (&list_init); @@ -1889,7 +2013,8 @@ void plugin_shutdown_all (void) * after callback returns. */ le = le->next; - (*callback) (); + if ((*callback) () != 0) + ret = -1; plugin_set_ctx (old_ctx); } @@ -1909,6 +2034,7 @@ void plugin_shutdown_all (void) plugin_free_loaded (); plugin_free_data_sets (); + return (ret); } /* void plugin_shutdown_all */ int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */ @@ -1964,8 +2090,10 @@ static int plugin_dispatch_values_internal (value_list_t *vl) int free_meta_data = 0; - if ((vl == NULL) || (vl->type[0] == 0) - || (vl->values == NULL) || (vl->values_len < 1)) + assert(vl); + assert(vl->plugin); + + if (vl->type[0] == 0 || vl->values == NULL || vl->values_len < 1) { ERROR ("plugin_dispatch_values: Invalid value list " "from plugin %s.", vl->plugin); @@ -2032,8 +2160,8 @@ static int plugin_dispatch_values_internal (value_list_t *vl) 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); } @@ -2086,7 +2214,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl) * don't get confused.. */ if (saved_values != NULL) { - free (vl->values); + sfree (vl->values); vl->values = saved_values; vl->values_len = saved_values_len; } @@ -2115,7 +2243,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl) * confused.. */ if (saved_values != NULL) { - free (vl->values); + sfree (vl->values); vl->values = saved_values; vl->values_len = saved_values_len; } @@ -2230,7 +2358,7 @@ int plugin_dispatch_multivalue (value_list_t const *template, /* {{{ */ assert (template->values_len == 1); - /* Calculate sum for Gauge to calculate percent if needed */ + /* Calculate sum for Gauge to calculate percent if needed */ if (DS_TYPE_GAUGE == store_type) { va_start (ap, store_type); while (42) @@ -2451,13 +2579,12 @@ static int plugin_notification_meta_add (notification_t *n, return (-1); } - meta = (notification_meta_t *) malloc (sizeof (notification_meta_t)); + meta = calloc (1, sizeof (*meta)); if (meta == NULL) { - ERROR ("plugin_notification_meta_add: malloc failed."); + ERROR ("plugin_notification_meta_add: calloc failed."); return (-1); } - memset (meta, 0, sizeof (notification_meta_t)); sstrncpy (meta->name, name, sizeof (meta->name)); meta->type = type; @@ -2554,14 +2681,12 @@ int plugin_notification_meta_add_boolean (notification_t *n, int plugin_notification_meta_copy (notification_t *dst, const notification_t *src) { - notification_meta_t *meta; - assert (dst != NULL); assert (src != NULL); assert (dst != src); assert ((src->meta == NULL) || (src->meta != dst->meta)); - for (meta = src->meta; meta != NULL; meta = meta->next) + for (notification_meta_t *meta = src->meta; meta != NULL; meta = meta->next) { if (meta->type == NM_TYPE_STRING) plugin_notification_meta_add_string (dst, meta->name, @@ -2601,7 +2726,11 @@ int plugin_notification_meta_free (notification_meta_t *n) 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); @@ -2708,7 +2837,7 @@ static void *plugin_thread_start (void *arg) plugin_set_ctx (plugin_thread->ctx); - free (plugin_thread); + sfree (plugin_thread); return start_routine (plugin_arg); } /* void *plugin_thread_start */