aboutsummaryrefslogtreecommitdiff
path: root/src/itc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/itc.c')
-rw-r--r--src/itc.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/itc.c b/src/itc.c
new file mode 100644
index 0000000..6171d4e
--- /dev/null
+++ b/src/itc.c
@@ -0,0 +1,104 @@
+#include "itc.h"
+#include "utils.h"
+
+#include <semaphore.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+struct itc {
+ int nslots;
+ void **slots;
+ int inputidx;
+ int outputidx;
+ sem_t emptied;
+ sem_t occupied;
+};
+
+itc *itc_alloc(int nslots)
+{
+ itc *ctx;
+
+ if (nslots <= 0) {
+ return NULL;
+ }
+
+ ctx = calloc(1, sizeof(*ctx));
+ ctx->nslots = nslots;
+ ctx->slots = calloc(nslots, sizeof(*ctx->slots));
+ sem_init(&ctx->emptied, 0, nslots);
+ sem_init(&ctx->occupied, 0, 0);
+
+ return ctx;
+}
+
+void itc_free(itc **ctx, itc_free_element free_element)
+{
+ if (ctx == NULL || *ctx == NULL) {
+ return;
+ }
+
+ itc_drop(*ctx, free_element);
+
+ sem_destroy(&(*ctx)->emptied);
+ sem_destroy(&(*ctx)->occupied);
+ free((*ctx)->slots);
+ free(*ctx);
+ *ctx = NULL;
+}
+
+void *itc_retrive(itc *ctx, int timeout_ms)
+{
+ struct timespec ts;
+ void *element;
+
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ timespec_add_ms(gettimespec(&ts), timeout_ms);
+
+ if (sem_timedwait(&ctx->occupied, &ts)) {
+ return NULL;
+ }
+ element = ctx->slots[ctx->outputidx];
+ ctx->outputidx = (ctx->outputidx + 1) % ctx->nslots;
+ sem_post(&ctx->emptied);
+
+ return element;
+}
+
+int itc_inject(itc *ctx, int timeout_ms, void *element)
+{
+ struct timespec ts;
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ timespec_add_ms(gettimespec(&ts), timeout_ms);
+
+ if (sem_timedwait(&ctx->emptied, &ts)) {
+ return -1;
+ }
+ ctx->slots[ctx->inputidx] = element;
+ ctx->inputidx = (ctx->inputidx + 1) % ctx->nslots;
+ sem_post(&ctx->occupied);
+
+ return 0;
+}
+
+void itc_drop(itc *ctx, itc_free_element free_element)
+{
+ void *element;
+
+ if (ctx == NULL) {
+ return;
+ }
+
+ while ((element = itc_retrive(ctx, 0)) != NULL) {
+ if (free_element != NULL) {
+ free_element(element);
+ }
+ }
+}
+