* point to the "base" thread */
static c_ithread_list_t *perl_threads = NULL;
+/* the key used to store each pthread's ithread */
+static pthread_key_t perl_thr_key;
+
static int perl_argc = 0;
static char **perl_argv = NULL;
{ "", 0 }
};
+struct {
+ char name[64];
+ char *var;
+} g_strings[] =
+{
+ { "Collectd::hostname_g", hostname_g },
+ { "", NULL }
+};
+
+struct {
+ char name[64];
+ int *var;
+} g_integers[] =
+{
+ { "Collectd::interval_g", &interval_g },
+ { "", NULL }
+};
+
/*
* Helper functions for data type conversion.
*/
status = snprintf (buf, buf_len, "%s", module);
else
status = snprintf (buf, buf_len, "%s::%s", base_name, module);
- if ((status < 0) || (status >= buf_len))
+ if ((status < 0) || ((unsigned int)status >= buf_len))
return (NULL);
buf[buf_len - 1] = '\0';
return (buf);
static int pplugin_register_data_set (pTHX_ char *name, AV *dataset)
{
int len = -1;
+ int ret = 0;
int i = 0;
data_source_t *ds = NULL;
set->ds_num = len + 1;
set->ds = ds;
- return plugin_register_data_set (set);
+
+ ret = plugin_register_data_set (set);
+
+ free (ds);
+ free (set);
+ return ret;
} /* static int pplugin_register_data_set (char *, SV *) */
/*
*/
/* must be called with perl_threads->mutex locked */
+static void c_ithread_destroy (c_ithread_t *ithread)
+{
+ dTHXa (ithread->interp);
+
+ assert (NULL != perl_threads);
+
+ PERL_SET_CONTEXT (aTHX);
+ log_debug ("Shutting down Perl interpreter %p...", aTHX);
+
+#if COLLECT_DEBUG
+ sv_report_used ();
+
+ --perl_threads->number_of_threads;
+#endif /* COLLECT_DEBUG */
+
+ perl_destruct (aTHX);
+ perl_free (aTHX);
+
+ if (NULL == ithread->prev)
+ perl_threads->head = ithread->next;
+ else
+ ithread->prev->next = ithread->next;
+
+ if (NULL == ithread->next)
+ perl_threads->tail = ithread->prev;
+ else
+ ithread->next->prev = ithread->prev;
+
+ sfree (ithread);
+ return;
+} /* static void c_ithread_destroy (c_ithread_t *) */
+
+static void c_ithread_destructor (void *arg)
+{
+ c_ithread_t *ithread = (c_ithread_t *)arg;
+ c_ithread_t *t = NULL;
+
+ if (NULL == perl_threads)
+ return;
+
+ pthread_mutex_lock (&perl_threads->mutex);
+
+ for (t = perl_threads->head; NULL != t; t = t->next)
+ if (t == ithread)
+ break;
+
+ /* the ithread no longer exists */
+ if (NULL == t)
+ return;
+
+ c_ithread_destroy (ithread);
+
+ pthread_mutex_unlock (&perl_threads->mutex);
+ return;
+} /* static void c_ithread_destructor (void *) */
+
+/* must be called with perl_threads->mutex locked */
static c_ithread_t *c_ithread_create (PerlInterpreter *base)
{
c_ithread_t *t = NULL;
+ dTHXa (NULL);
assert (NULL != perl_threads);
? NULL
: perl_clone (base, CLONEf_KEEP_PTR_TABLE);
+ aTHX = t->interp;
+
+ if (NULL != base) {
+ av_clear (PL_endav);
+ av_undef (PL_endav);
+ PL_endav = Nullav;
+ }
+
#if COLLECT_DEBUG
++perl_threads->number_of_threads;
#endif /* COLLECT_DEBUG */
}
perl_threads->tail = t;
+
+ pthread_setspecific (perl_thr_key, (const void *)t);
return t;
} /* static c_ithread_t *c_ithread_create (PerlInterpreter *) */
t = perl_threads->tail;
while (NULL != t) {
- aTHX = t->interp;
- PERL_SET_CONTEXT (aTHX);
-
-#if COLLECT_DEBUG
- sv_report_used ();
-#endif /* COLLECT_DEBUG */
-
- perl_destruct (aTHX);
- perl_free (aTHX);
+ c_ithread_t *thr = t;
+ /* the pointer has to be advanced before destroying
+ * the thread as this will free the memory */
t = t->prev;
- sfree (t);
+ c_ithread_destroy (thr);
}
pthread_mutex_unlock (&perl_threads->mutex);
+ pthread_mutex_destroy (&perl_threads->mutex);
sfree (perl_threads);
+ pthread_key_delete (perl_thr_key);
+
PERL_SYS_TERM ();
plugin_unregister_shutdown ("perl");
return ret;
} /* static void perl_shutdown (void) */
+/*
+ * Access functions for global variables.
+ *
+ * These functions implement the "magic" used to access
+ * the global variables from Perl.
+ */
+
+static int g_pv_get (pTHX_ SV *var, MAGIC *mg)
+{
+ char *pv = mg->mg_ptr;
+ sv_setpv (var, pv);
+ return 0;
+} /* static int g_pv_get (pTHX_ SV *, MAGIC *) */
+
+static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
+{
+ char *pv = mg->mg_ptr;
+ strncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
+ pv[DATA_MAX_NAME_LEN - 1] = '\0';
+ return 0;
+} /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
+
+static int g_iv_get (pTHX_ SV *var, MAGIC *mg)
+{
+ int *iv = (int *)mg->mg_ptr;
+ sv_setiv (var, *iv);
+ return 0;
+} /* static int g_iv_get (pTHX_ SV *, MAGIC *) */
+
+static int g_iv_set (pTHX_ SV *var, MAGIC *mg)
+{
+ int *iv = (int *)mg->mg_ptr;
+ *iv = (int)SvIV (var);
+ return 0;
+} /* static int g_iv_set (pTHX_ SV *, MAGIC *) */
+
+static MGVTBL g_pv_vtbl = { g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL };
+static MGVTBL g_iv_vtbl = { g_iv_get, g_iv_set, NULL, NULL, NULL, NULL, NULL };
+
/* bootstrap the Collectd module */
static void xs_init (pTHX)
{
HV *stash = NULL;
+ SV *tmp = NULL;
char *file = __FILE__;
int i = 0;
/* export "constants" */
for (i = 0; '\0' != constants[i].name[0]; ++i)
newCONSTSUB (stash, constants[i].name, newSViv (constants[i].value));
+
+ /* export global variables
+ * by adding "magic" to the SV's representing the globale variables
+ * perl is able to automagically call the get/set function when
+ * accessing any such variable (this is basically the same as using
+ * tie() in Perl) */
+ /* global strings */
+ for (i = 0; '\0' != g_strings[i].name[0]; ++i) {
+ tmp = get_sv (g_strings[i].name, 1);
+ sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_pv_vtbl,
+ g_strings[i].var, 0);
+ }
+
+ /* global integers */
+ for (i = 0; '\0' != g_integers[i].name[0]; ++i) {
+ tmp = get_sv (g_integers[i].name, 1);
+ sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_iv_vtbl,
+ (char *)g_integers[i].var, 0);
+ }
return;
} /* static void xs_init (pTHX) */
}
#endif /* COLLECT_DEBUG */
+ if (0 != pthread_key_create (&perl_thr_key, c_ithread_destructor)) {
+ log_err ("init_pi: pthread_key_create failed");
+
+ /* this must not happen - cowardly giving up if it does */
+ exit (1);
+ }
+
PERL_SYS_INIT3 (&argc, &argv, &environ);
perl_threads = (c_ithread_list_t *)smalloc (sizeof (c_ithread_list_t));
perl_threads->tail = perl_threads->head;
if (NULL == (perl_threads->head->interp = perl_alloc ())) {
- log_err ("module_register: Not enough memory.");
+ log_err ("init_pi: Not enough memory.");
exit (3);
}
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
if (0 != perl_parse (aTHX_ xs_init, argc, argv, NULL)) {
- log_err ("module_register: Unable to bootstrap Collectd.");
+ log_err ("init_pi: Unable to bootstrap Collectd.");
exit (1);
}
char *value = NULL;
if ((0 != ci->children_num) || (1 != ci->values_num)
- || (OCONFIG_TYPE_STRING != ci->values[0].type))
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("LoadPlugin expects a single string argument.");
return 1;
+ }
value = ci->values[0].value.string;
char *value = NULL;
if ((0 != ci->children_num) || (1 != ci->values_num)
- || (OCONFIG_TYPE_STRING != ci->values[0].type))
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("BaseName expects a single string argument.");
return 1;
+ }
value = ci->values[0].value.string;
char *value = NULL;
if ((0 != ci->children_num) || (1 != ci->values_num)
- || (OCONFIG_TYPE_STRING != ci->values[0].type))
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("EnableDebugger expects a single string argument.");
return 1;
+ }
value = ci->values[0].value.string;
char *value = NULL;
if ((0 != ci->children_num) || (1 != ci->values_num)
- || (OCONFIG_TYPE_STRING != ci->values[0].type))
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("IncludeDir expects a single string argument.");
return 1;
+ }
value = ci->values[0].value.string;