[PATCH 1/2] lib: Fix deadlock in threadpool manager

  • From: Dimitri Staessens <dimitri@ouroboros.rocks>
  • To: ouroboros@xxxxxxxxxxxxx
  • Date: Sun, 8 Mar 2020 14:24:54 +0100

There was a rare deadlock upon destruction of the threadpool manager
because the threads were cancelled/joined under lock.

Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
---
 src/lib/tpm.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/src/lib/tpm.c b/src/lib/tpm.c
index ca2eb1e..0ba9619 100644
--- a/src/lib/tpm.c
+++ b/src/lib/tpm.c
@@ -82,11 +82,19 @@ static void tpm_join(struct tpm * tpm)
                                 --tpm->cur;
                         }
                 }
+        }
 
+        list_for_each_safe(p, h, &tpm->pool) {
+                struct pthr_el * e = list_entry(p, struct pthr_el, next);
                 if (e->kill) {
-                        pthread_join(e->thr, NULL);
+                        pthread_t thr = e->thr;
                         list_del(&e->next);
                         free(e);
+                        pthread_mutex_unlock(&tpm->lock);
+
+                        pthread_join(thr, NULL);
+
+                        pthread_mutex_lock(&tpm->lock);
                 }
         }
 }
@@ -256,29 +264,35 @@ static struct pthr_el * tpm_pthr_el(struct tpm * tpm,
 
         }
 
-        assert(false);
-
         return NULL;
 }
 
 void tpm_inc(struct tpm * tpm)
 {
+        struct pthr_el * e;
+
         pthread_mutex_lock(&tpm->lock);
 
-        tpm_pthr_el(tpm, pthread_self())->busy = false;
-
-        --tpm->wrk;
+        e = tpm_pthr_el(tpm, pthread_self());
+        if (e != NULL) {
+                e->busy = false;
+                --tpm->wrk;
+        }
 
         pthread_mutex_unlock(&tpm->lock);
 }
 
 void tpm_dec(struct tpm * tpm)
 {
+        struct pthr_el * e;
+
         pthread_mutex_lock(&tpm->lock);
 
-        tpm_pthr_el(tpm, pthread_self())->busy = true;
-
-        ++tpm->wrk;
+        e = tpm_pthr_el(tpm, pthread_self());
+        if (e != NULL) {
+                e->busy = true;
+                ++tpm->wrk;
+        }
 
         pthread_cond_signal(&tpm->cond);
 
-- 
2.25.1


Other related posts:

  • » [PATCH 1/2] lib: Fix deadlock in threadpool manager - Dimitri Staessens