Merge branch 'collectd-4.9' into collectd-4.10
[collectd.git] / src / plugin.c
index 5d882e6..af894d5 100644 (file)
@@ -59,6 +59,7 @@ struct read_func_s
 #define rf_callback rf_super.cf_callback
 #define rf_udata rf_super.cf_udata
        callback_func_t rf_super;
+       char rf_group[DATA_MAX_NAME_LEN];
        char rf_name[DATA_MAX_NAME_LEN];
        int rf_type;
        struct timespec rf_interval;
@@ -151,7 +152,7 @@ static void destroy_read_heap (void) /* {{{ */
        {
                callback_func_t *cf;
 
-               cf = c_head_get_root (read_heap);
+               cf = c_heap_get_root (read_heap);
                if (cf == NULL)
                        break;
 
@@ -173,7 +174,7 @@ static int register_callback (llist_t **list, /* {{{ */
                *list = llist_create ();
                if (*list == NULL)
                {
-                       ERROR ("plugin: create_register_callback: "
+                       ERROR ("plugin: register_callback: "
                                        "llist_create failed.");
                        destroy_callback (cf);
                        return (-1);
@@ -183,7 +184,7 @@ static int register_callback (llist_t **list, /* {{{ */
        key = strdup (name);
        if (key == NULL)
        {
-               ERROR ("plugin: create_register_callback: strdup failed.");
+               ERROR ("plugin: register_callback: strdup failed.");
                destroy_callback (cf);
                return (-1);
        }
@@ -194,7 +195,7 @@ static int register_callback (llist_t **list, /* {{{ */
                le = llentry_create (key, cf);
                if (le == NULL)
                {
-                       ERROR ("plugin: create_register_callback: "
+                       ERROR ("plugin: register_callback: "
                                        "llentry_create failed.");
                        free (key);
                        destroy_callback (cf);
@@ -210,6 +211,10 @@ static int register_callback (llist_t **list, /* {{{ */
                old_cf = le->value;
                le->value = cf;
 
+               WARNING ("plugin: register_callback: "
+                               "a callback named `%s' already exists - "
+                               "overwriting the old entry!", name);
+
                destroy_callback (old_cf);
                sfree (key);
        }
@@ -270,7 +275,7 @@ static int plugin_unregister (llist_t *list, const char *name) /* {{{ */
  * object, but it will bitch about a shared object not having a
  * ``module_register'' symbol..
  */
-static int plugin_load_file (char *file)
+static int plugin_load_file (char *file, uint32_t flags)
 {
        lt_dlhandle dlh;
        void (*reg_handle) (void);
@@ -280,7 +285,24 @@ static int plugin_load_file (char *file)
        lt_dlinit ();
        lt_dlerror (); /* clear errors */
 
-       if ((dlh = lt_dlopen (file)) == NULL)
+#if LIBTOOL_VERSION == 2
+       if (flags & PLUGIN_FLAGS_GLOBAL) {
+               lt_dladvise advise;
+               lt_dladvise_init(&advise);
+               lt_dladvise_global(&advise);
+               dlh = lt_dlopenadvise(file, advise);
+               lt_dladvise_destroy(&advise);
+       } else {
+               dlh = lt_dlopen (file);
+       }
+#else /* if LIBTOOL_VERSION == 1 */
+       if (flags & PLUGIN_FLAGS_GLOBAL)
+               ERROR ("plugin_load_file: The global flag is not supported, "
+                               "libtool 2 is required for this.");
+       dlh = lt_dlopen (file);
+#endif
+
+       if (dlh == NULL)
        {
                const char *error = lt_dlerror ();
 
@@ -302,6 +324,13 @@ static int plugin_load_file (char *file)
        return (0);
 }
 
+static _Bool timeout_reached(struct timespec timeout)
+{
+       struct timeval now;
+       gettimeofday(&now, NULL);
+       return (now.tv_sec >= timeout.tv_sec && now.tv_usec >= (timeout.tv_nsec / 1000));
+}
+
 static void *plugin_read_thread (void __attribute__((unused)) *args)
 {
        while (read_loop != 0)
@@ -310,9 +339,10 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                struct timeval now;
                int status;
                int rf_type;
+               int rc;
 
                /* Get the read function that needs to be read next. */
-               rf = c_head_get_root (read_heap);
+               rf = c_heap_get_root (read_heap);
                if (rf == NULL)
                {
                        struct timespec abstime;
@@ -345,9 +375,20 @@ static void *plugin_read_thread (void __attribute__((unused)) *args)
                /* sleep until this entry is due,
                 * using pthread_cond_timedwait */
                pthread_mutex_lock (&read_lock);
-               pthread_cond_timedwait (&read_cond, &read_lock,
+               /* In pthread_cond_timedwait, spurious wakeups are possible
+                * (and really happen, at least on NetBSD with > 1 CPU), thus
+                * we need to re-evaluate the condition every time
+                * pthread_cond_timedwait returns. */
+               rc = 0;
+               while ((read_loop != 0)
+                               && !timeout_reached(rf->rf_next_read)
+                               && rc == 0)
+               {
+                       rc = pthread_cond_timedwait (&read_cond, &read_lock,
                                &rf->rf_next_read);
-               /* Must hold `real_lock' when accessing `rf->rf_type'. */
+               }
+
+               /* Must hold `read_lock' when accessing `rf->rf_type'. */
                rf_type = rf->rf_type;
                pthread_mutex_unlock (&read_lock);
 
@@ -535,7 +576,7 @@ void plugin_set_dir (const char *dir)
 }
 
 #define BUFSIZE 512
-int plugin_load (const char *type)
+int plugin_load (const char *type, uint32_t flags)
 {
        DIR  *dh;
        const char *dir;
@@ -597,7 +638,7 @@ int plugin_load (const char *type)
                        continue;
                }
 
-               if (plugin_load_file (filename) == 0)
+               if (plugin_load_file (filename, flags) == 0)
                {
                        /* success */
                        ret = 0;
@@ -735,6 +776,7 @@ int plugin_register_read (const char *name,
        rf->rf_callback = (void *) callback;
        rf->rf_udata.data = NULL;
        rf->rf_udata.free_func = NULL;
+       rf->rf_group[0] = '\0';
        sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
        rf->rf_type = RF_SIMPLE;
        rf->rf_interval.tv_sec = 0;
@@ -744,7 +786,7 @@ int plugin_register_read (const char *name,
        return (plugin_insert_read (rf));
 } /* int plugin_register_read */
 
-int plugin_register_complex_read (const char *name,
+int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
                const struct timespec *interval,
                user_data_t *user_data)
@@ -760,6 +802,10 @@ int plugin_register_complex_read (const char *name,
 
        memset (rf, 0, sizeof (read_func_t));
        rf->rf_callback = (void *) callback;
+       if (group != NULL)
+               sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
+       else
+               rf->rf_group[0] = '\0';
        sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
        rf->rf_type = RF_COMPLEX;
        if (interval != NULL)
@@ -911,6 +957,67 @@ int plugin_unregister_read (const char *name) /* {{{ */
        return (0);
 } /* }}} int plugin_unregister_read */
 
+static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */
+{
+       read_func_t *rf    = e->value;
+       char        *group = ud;
+
+       return strcmp (rf->rf_group, (const char *)group);
+} /* }}} int compare_read_func_group */
+
+int plugin_unregister_read_group (const char *group) /* {{{ */
+{
+       llentry_t *le;
+       read_func_t *rf;
+
+       int found = 0;
+
+       if (group == NULL)
+               return (-ENOENT);
+
+       pthread_mutex_lock (&read_lock);
+
+       if (read_list == NULL)
+       {
+               pthread_mutex_unlock (&read_lock);
+               return (-ENOENT);
+       }
+
+       while (42)
+       {
+               le = llist_search_custom (read_list,
+                               compare_read_func_group, (void *)group);
+
+               if (le == NULL)
+                       break;
+
+               ++found;
+
+               llist_remove (read_list, le);
+
+               rf = le->value;
+               assert (rf != NULL);
+               rf->rf_type = RF_REMOVE;
+
+               llentry_destroy (le);
+
+               DEBUG ("plugin_unregister_read_group: "
+                               "Marked `%s' (group `%s') for removal.",
+                               rf->rf_name, group);
+       }
+
+       pthread_mutex_unlock (&read_lock);
+
+       if (found == 0)
+       {
+               WARNING ("plugin_unregister_read_group: No such "
+                               "group of read function: %s", group);
+               return (-ENOENT);
+       }
+
+       return (0);
+} /* }}} int plugin_unregister_read_group */
+
 int plugin_unregister_write (const char *name)
 {
        return (plugin_unregister (list_write, name));
@@ -1036,7 +1143,7 @@ int plugin_read_all_once (void)
        {
                read_func_t *rf;
 
-               rf = c_head_get_root (read_heap);
+               rf = c_heap_get_root (read_heap);
                if (rf == NULL)
                        break;
 
@@ -1267,7 +1374,12 @@ int plugin_dispatch_values (value_list_t *vl)
 
        if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
        {
-               INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type);
+               char ident[6 * DATA_MAX_NAME_LEN];
+
+               FORMAT_VL (ident, sizeof (ident), vl);
+               INFO ("plugin_dispatch_values: Dataset not found: %s "
+                               "(from \"%s\"), check your types.db!",
+                               vl->type, ident);
                return (-1);
        }
 
@@ -1443,9 +1555,6 @@ void plugin_log (int level, const char *format, ...)
        va_list ap;
        llentry_t *le;
 
-       if (list_log == NULL)
-               return;
-
 #if !COLLECT_DEBUG
        if (level >= LOG_DEBUG)
                return;
@@ -1456,6 +1565,12 @@ void plugin_log (int level, const char *format, ...)
        msg[sizeof (msg) - 1] = '\0';
        va_end (ap);
 
+       if (list_log == NULL)
+       {
+               fprintf (stderr, "%s\n", msg);
+               return;
+       }
+
        le = llist_head (list_log);
        while (le != NULL)
        {