diff options
author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2020-03-08 14:24:54 +0100 |
---|---|---|
committer | Sander Vrijders <sander@ouroboros.rocks> | 2020-03-14 15:38:14 +0100 |
commit | 9fac3ad2a05c9025acdad6feae3932711dbcd561 (patch) | |
tree | 5e9cc92ecf060856c2b89d3d1042592bdedc2b93 /src/lib/tpm.c | |
parent | fe6b60909d455abdac7885ceaba1097749e7aeb1 (diff) | |
download | ouroboros-9fac3ad2a05c9025acdad6feae3932711dbcd561.tar.gz ouroboros-9fac3ad2a05c9025acdad6feae3932711dbcd561.zip |
lib: Fix deadlock in threadpool manager
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>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/lib/tpm.c')
-rw-r--r-- | src/lib/tpm.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/lib/tpm.c b/src/lib/tpm.c index ca2eb1ef..0ba9619b 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) { - pthread_mutex_lock(&tpm->lock); + struct pthr_el * e; - tpm_pthr_el(tpm, pthread_self())->busy = false; + pthread_mutex_lock(&tpm->lock); - --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) { - pthread_mutex_lock(&tpm->lock); + struct pthr_el * e; - tpm_pthr_el(tpm, pthread_self())->busy = true; + pthread_mutex_lock(&tpm->lock); - ++tpm->wrk; + e = tpm_pthr_el(tpm, pthread_self()); + if (e != NULL) { + e->busy = true; + ++tpm->wrk; + } pthread_cond_signal(&tpm->cond); |