summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: e58ebe6)
raw | patch | inline | side by side (parent: e58ebe6)
author | Pavel Rochnyack <pavel2000@ngs.ru> | |
Fri, 13 May 2016 13:20:22 +0000 (19:20 +0600) | ||
committer | Pavel Rochnyack <pavel2000@ngs.ru> | |
Sun, 29 May 2016 06:27:19 +0000 (12:27 +0600) |
* Fix coredump due to destroying interpreter on threads running perl.
* Fix deadlock when perl_log() is called from perl_init()
* Fix deadlock when perl_log() is called from perl_init()
src/perl.c | patch | blob | history |
diff --git a/src/perl.c b/src/perl.c
index 0b5debe67730ce99e218bde5a41461b51e16ec3d..c5b9d2ab2099efc9eb9800360ccf26e4c812871b 100644 (file)
--- a/src/perl.c
+++ b/src/perl.c
-/*
+/**
* 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);
}