summaryrefslogtreecommitdiff
path: root/src/lib/tpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/tpm.c')
-rw-r--r--src/lib/tpm.c197
1 files changed, 136 insertions, 61 deletions
diff --git a/src/lib/tpm.c b/src/lib/tpm.c
index 0ef1fda8..7a17ef6b 100644
--- a/src/lib/tpm.c
+++ b/src/lib/tpm.c
@@ -26,21 +26,32 @@
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
+#include <ouroboros/pthread.h>
#include <ouroboros/time.h>
#include <ouroboros/tpm.h>
+#ifdef CONFIG_OUROBOROS_DEBUG
+#define OUROBOROS_PREFIX "tpm"
+#include <ouroboros/logs.h>
+#endif
+
#include <assert.h>
-#include <pthread.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-#define TPM_TIMEOUT 1000
+#define TPM_TIMEOUT 1000
struct pthr_el {
struct list_head next;
bool kill;
bool busy;
-
+ bool wait;
+#ifdef CONFIG_OUROBOROS_DEBUG
+ struct timespec start;
+ struct timespec last;
+#endif
pthread_t thr;
};
@@ -63,16 +74,45 @@ struct tpm {
enum tpm_state state;
pthread_cond_t cond;
- pthread_mutex_t lock;
+ pthread_mutex_t mtx;
pthread_t mgr;
};
+#ifdef CONFIG_OUROBOROS_DEBUG
+#define BETWEEN(a, x, y) ((a) > (x) && (a) <= (y))
+static void tpm_debug_thread(struct pthr_el * e)
+{
+ struct timespec now;
+ time_t diff;
+ time_t intv;
+
+ if (e->wait || !e->busy)
+ return;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ diff = ts_diff_ms(&now, &e->start) / 1000;
+ intv = ts_diff_ms(&now, &e->last) / 1000;
+
+ (void) diff; /* Never read if both build options off (0) */
+ (void) intv; /* Never read if report option off (0) */
+
+ if (BETWEEN(TPM_DEBUG_REPORT_INTERVAL, 0, intv)) {
+ log_dbg("Thread %d:%lx running for %ld s.\n",
+ getpid(),e->thr, diff);
+ e->last = now;
+ }
+
+ if (BETWEEN(TPM_DEBUG_ABORT_TIMEOUT, 0, diff))
+ assert(false); /* TODO: Grab a coffee and fire up GDB */
+}
+#endif
+
static void tpm_join(struct tpm * tpm)
{
struct list_head * p;
struct list_head * h;
-
list_for_each_safe(p, h, &tpm->pool) {
struct pthr_el * e = list_entry(p, struct pthr_el, next);
if (tpm->state != TPM_RUNNING) {
@@ -86,15 +126,18 @@ static void tpm_join(struct tpm * tpm)
list_for_each_safe(p, h, &tpm->pool) {
struct pthr_el * e = list_entry(p, struct pthr_el, next);
+#ifdef CONFIG_OUROBOROS_DEBUG
+ tpm_debug_thread(e);
+#endif
if (e->kill) {
pthread_t thr = e->thr;
list_del(&e->next);
free(e);
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
pthread_join(thr, NULL);
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
}
}
}
@@ -114,56 +157,59 @@ static void tpm_kill(struct tpm * tpm)
}
}
-static void * tpmgr(void * o)
+static int __tpm(struct tpm * tpm)
{
struct timespec dl;
struct timespec to = TIMESPEC_INIT_MS(TPM_TIMEOUT);
- struct tpm * tpm = (struct tpm *) o;
-
- while (true) {
- clock_gettime(PTHREAD_COND_CLOCK, &dl);
- ts_add(&dl, &to, &dl);
- pthread_mutex_lock(&tpm->lock);
+ clock_gettime(PTHREAD_COND_CLOCK, &dl);
+ ts_add(&dl, &to, &dl);
- if (tpm->state != TPM_RUNNING) {
- tpm_join(tpm);
- pthread_mutex_unlock(&tpm->lock);
- break;
- }
+ pthread_mutex_lock(&tpm->mtx);
+ if (tpm->state != TPM_RUNNING) {
tpm_join(tpm);
+ pthread_mutex_unlock(&tpm->mtx);
+ return -1;
+ }
- if (tpm->cur - tpm->wrk < tpm->min) {
- size_t i;
- for (i = 0; i < tpm->inc; ++i) {
- struct pthr_el * e = malloc(sizeof(*e));
- if (e == NULL)
- break;
+ tpm_join(tpm);
- e->kill = false;
- e->busy = false;
+ if (tpm->cur - tpm->wrk < tpm->min) {
+ size_t i;
+ for (i = 0; i < tpm->inc; ++i) {
+ struct pthr_el * e = malloc(sizeof(*e));
+ if (e == NULL)
+ break;
- if (pthread_create(&e->thr, NULL,
- tpm->func, tpm->o)) {
- free(e);
- break;
- }
+ memset(e, 0, sizeof(*e));
- list_add(&e->next, &tpm->pool);
+ if (pthread_create(&e->thr, NULL, tpm->func, tpm->o)) {
+ free(e);
+ break;
}
- tpm->cur += i;
+ list_add(&e->next, &tpm->pool);
}
- if (pthread_cond_timedwait(&tpm->cond, &tpm->lock, &dl)
- == ETIMEDOUT)
- if (tpm->cur - tpm->wrk > tpm->min)
- tpm_kill(tpm);
-
- pthread_mutex_unlock(&tpm->lock);
+ tpm->cur += i;
}
+ pthread_cleanup_push(__cleanup_mutex_unlock, &tpm->mtx);
+
+ if (pthread_cond_timedwait(&tpm->cond, &tpm->mtx, &dl) == ETIMEDOUT)
+ if (tpm->cur - tpm->wrk > tpm->min)
+ tpm_kill(tpm);
+
+ pthread_cleanup_pop(true);
+
+ return 0;
+}
+
+static void * tpmgr(void * o)
+{
+ while (__tpm((struct tpm *) o) == 0);
+
return (void *) 0;
}
@@ -175,11 +221,14 @@ struct tpm * tpm_create(size_t min,
struct tpm * tpm;
pthread_condattr_t cattr;
+ assert(func != NULL);
+ assert(inc > 0);
+
tpm = malloc(sizeof(*tpm));
if (tpm == NULL)
goto fail_malloc;
- if (pthread_mutex_init(&tpm->lock, NULL))
+ if (pthread_mutex_init(&tpm->mtx, NULL))
goto fail_lock;
if (pthread_condattr_init(&cattr))
@@ -208,7 +257,7 @@ struct tpm * tpm_create(size_t min,
fail_cond:
pthread_condattr_destroy(&cattr);
fail_cattr:
- pthread_mutex_destroy(&tpm->lock);
+ pthread_mutex_destroy(&tpm->mtx);
fail_lock:
free(tpm);
fail_malloc:
@@ -217,34 +266,39 @@ struct tpm * tpm_create(size_t min,
int tpm_start(struct tpm * tpm)
{
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
if (pthread_create(&tpm->mgr, NULL, tpmgr, tpm)) {
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
return -1;
}
tpm->state = TPM_RUNNING;
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
return 0;
}
void tpm_stop(struct tpm * tpm)
{
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
+
+ if (tpm->state != TPM_RUNNING) {
+ pthread_mutex_unlock(&tpm->mtx);
+ return;
+ }
tpm->state = TPM_NULL;
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
pthread_join(tpm->mgr, NULL);
}
void tpm_destroy(struct tpm * tpm)
{
- pthread_mutex_destroy(&tpm->lock);
+ pthread_mutex_destroy(&tpm->mtx);
pthread_cond_destroy(&tpm->cond);
free(tpm);
@@ -260,40 +314,61 @@ static struct pthr_el * tpm_pthr_el(struct tpm * tpm,
e = list_entry(p, struct pthr_el, next);
if (e->thr == thr)
return e;
-
}
return NULL;
}
-void tpm_inc(struct tpm * tpm)
+void tpm_begin_work(struct tpm * tpm)
{
struct pthr_el * e;
- pthread_mutex_lock(&tpm->lock);
+#ifdef CONFIG_OUROBOROS_DEBUG
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+#endif
+
+ pthread_mutex_lock(&tpm->mtx);
e = tpm_pthr_el(tpm, pthread_self());
if (e != NULL) {
- e->busy = false;
- --tpm->wrk;
+ e->busy = true;
+ ++tpm->wrk;
+#ifdef CONFIG_OUROBOROS_DEBUG
+ e->start = now;
+ e->last = now;
+#endif
}
- pthread_mutex_unlock(&tpm->lock);
+ pthread_cond_signal(&tpm->cond);
+
+ pthread_mutex_unlock(&tpm->mtx);
}
-void tpm_dec(struct tpm * tpm)
+void tpm_wait_work(struct tpm * tpm)
{
struct pthr_el * e;
- pthread_mutex_lock(&tpm->lock);
+ pthread_mutex_lock(&tpm->mtx);
+
+ e = tpm_pthr_el(tpm, pthread_self());
+ if (e != NULL)
+ e->wait = true;
+
+ pthread_mutex_unlock(&tpm->mtx);
+}
+
+void tpm_end_work(struct tpm * tpm)
+{
+ struct pthr_el * e;
+
+ pthread_mutex_lock(&tpm->mtx);
e = tpm_pthr_el(tpm, pthread_self());
if (e != NULL) {
- e->busy = true;
- ++tpm->wrk;
+ e->busy = false;
+ --tpm->wrk;
}
- pthread_cond_signal(&tpm->cond);
-
- pthread_mutex_unlock(&tpm->lock);
+ pthread_mutex_unlock(&tpm->mtx);
}