-/*
+/**
* collectd - src/perl.c
* Copyright (C) 2007-2009 Sebastian Harl
*
typedef struct c_ithread_s {
/* the thread's Perl interpreter */
PerlInterpreter *interp;
+ _Bool running; /* thread is inside pi */
+ _Bool shutdown;
+ pthread_t pthread;
/* double linked list of threads */
struct c_ithread_s *prev;
{
int retvals = 0;
+ _Bool old_running;
va_list ap;
int ret = 0;
dSP;
+ c_ithread_t *t = (c_ithread_t *)pthread_getspecific(perl_thr_key);
+ if (t == NULL) /* thread destroyed ( c_ithread_destroy*() -> log_debug() ) */
+ return 0;
+
+ old_running = t->running;
+ t->running = 1;
+
+ if (t->shutdown) {
+ t->running = old_running;
+ return 0;
+ }
+
if ((type < 0) || (type >= PLUGIN_TYPES))
return -1;
FREETMPS;
LEAVE;
+ t->running = old_running;
va_end (ap);
return ret;
} /* static int pplugin_call_all (int, ...) */
t->prev = perl_threads->tail;
}
+ t->pthread = pthread_self();
+ t->running = 0;
+ t->shutdown = 0;
perl_threads->tail = t;
pthread_setspecific (perl_thr_key, (const void *)t);
{
int retvals = 0;
+ _Bool old_running;
va_list ap;
int ret = 0;
dSP;
+ c_ithread_t *t = (c_ithread_t *)pthread_getspecific(perl_thr_key);
+ if (t == NULL) /* thread destroyed */
+ return 0;
+
+ old_running = t->running;
+ t->running = 1;
+
+ if (t->shutdown) {
+ t->running = old_running;
+ return 0;
+ }
+
if ((type < 0) || (type >= FC_TYPES))
return -1;
FREETMPS;
LEAVE;
+ t->running = old_running;
va_end (ap);
return ret;
} /* static int fc_call (int, int, pfc_user_data_t *, ...) */
/* Lock the base thread to avoid race conditions with c_ithread_create().
* See https://github.com/collectd/collectd/issues/9 and
- * https://github.com/collectd/collectd/issues/1706 for details. */
-
+ * https://github.com/collectd/collectd/issues/1706 for details.
+ * Locking here requires additional check in perl_log() to avoid deadlock.
+ */
assert (aTHX == perl_threads->head->interp);
pthread_mutex_lock (&perl_threads->mutex);
user_data_t __attribute__((unused)) *user_data)
{
dTHX;
+ int locked = 0;
if (NULL == perl_threads)
return;
/* Lock the base thread if this is not called from one of the read threads
* to avoid race conditions with c_ithread_create(). See
- * https://github.com/collectd/collectd/issues/9 for details. */
- if (aTHX == perl_threads->head->interp)
+ * https://github.com/collectd/collectd/issues/9 for details.
+ * Additionally check, if we are called from perl interpreter.
+ * Maybe PTHREAD_MUTEX_RECURSIVE mutex type will be more appropriate?
+ */
+
+ if (aTHX == perl_threads->head->interp && !perl_threads->head->running) {
pthread_mutex_lock (&perl_threads->mutex);
+ locked = 1;
+ }
pplugin_call_all (aTHX_ PLUGIN_LOG, level, msg);
- if (aTHX == perl_threads->head->interp)
+ if (locked)
pthread_mutex_unlock (&perl_threads->mutex);
return;
t = perl_threads->tail;
while (NULL != t) {
+ struct timespec ts_wait;
c_ithread_t *thr = t;
/* the pointer has to be advanced before destroying
* the thread as this will free the memory */
t = t->prev;
+ thr->shutdown = 1;
+ if (thr->running) {
+ /* Give some time to thread to exit from pi */
+ WARNING ("perl shutdown: thread is running inside perl. Waiting.");
+ ts_wait.tv_sec = 0;
+ ts_wait.tv_nsec = 500000;
+ nanosleep (&ts_wait, NULL);
+ }
+ if (thr->running) {
+ /* This will crash collectd process later due to PERL_SYS_TERM() */
+ //ERROR ("perl shutdown: thread hangs inside perl. "
+ // "Skipped perl interpreter destroy.");
+ //continue;
+
+ ERROR ("perl shutdown: thread hangs inside perl. Thread killed.");
+ pthread_kill (thr->pthread, SIGTERM);
+ }
c_ithread_destroy (thr);
}