From 318ad3ab3a83041f83f824de2568b332407d0f37 Mon Sep 17 00:00:00 2001 From: Maas-Maarten Zeeman Date: Tue, 18 Oct 2011 10:43:48 +0200 Subject: [PATCH] Work in progress --- c_src/queue.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++ c_src/queue.h | 24 ++++++ 2 files changed, 231 insertions(+) create mode 100644 c_src/queue.c create mode 100644 c_src/queue.h diff --git a/c_src/queue.c b/c_src/queue.c new file mode 100644 index 0000000..7214ec6 --- /dev/null +++ b/c_src/queue.c @@ -0,0 +1,207 @@ +// This file is part of Emonk released under the MIT license. +// See the LICENSE file for more information. + +/* Adapted by: Maas-Maarten Zeeman +#include + +#include "queue.h" + +struct qitem_t +{ + struct qitem_t* next; + void* data; +}; + +typedef struct qitem_t qitem; + +struct queue_t +{ + ErlNifMutex *lock; + ErlNifCond *cond; + qitem *head; + qitem *tail; + void *message; + int length; +}; + +queue * +queue_create() +{ + queue *ret; + + ret = (queue *) enif_alloc(sizeof(struct queue_t)); + if(ret == NULL) + goto error; + + ret->lock = NULL; + ret->cond = NULL; + ret->head = NULL; + ret->tail = NULL; + ret->message = NULL; + ret->length = 0; + + ret->lock = enif_mutex_create("queue_lock"); + if(ret->lock == NULL) + goto error; + + ret->cond = enif_cond_create("queue_cond"); + if(ret->cond == NULL) + goto error; + + return ret; + +error: + if(ret->lock != NULL) + enif_mutex_destroy(ret->lock); + if(ret->cond != NULL) + enif_cond_destroy(ret->cond); + if(ret != NULL) + enif_free(ret); + return NULL; +} + +void +queue_destroy(queue *queue) +{ + ErlNifMutex *lock; + ErlNifCond *cond; + int length; + + enif_mutex_lock(queue->lock); + lock = queue->lock; + cond = queue->cond; + length = queue->length; + + queue->lock = NULL; + queue->cond = NULL; + queue->head = NULL; + queue->tail = NULL; + queue->length = -1; + enif_mutex_unlock(lock); + + assert(length == 0 && "Attempting to destroy a non-empty queue."); + enif_cond_destroy(cond); + enif_mutex_destroy(lock); + enif_free(queue); +} + +int +queue_has_item(queue *queue) +{ + int ret; + + enif_mutex_lock(queue->lock); + ret = (queue->head != NULL); + enif_mutex_unlock(queue->lock); + + return ret; +} + +int +queue_push(queue *queue, void *item) +{ + qitem * entry = (qitem *) enif_alloc(sizeof(struct qitem_t)); + if(entry == NULL) + return 0; + + entry->data = item; + entry->next = NULL; + + enif_mutex_lock(queue->lock); + + assert(queue->length >= 0 && "Invalid queue size at push"); + + if(queue->tail != NULL) + { + queue->tail->next = entry; + } + + queue->tail = entry; + + if(queue->head == NULL) + { + queue->head = queue->tail; + } + + queue->length += 1; + + enif_cond_signal(queue->cond); + enif_mutex_unlock(queue->lock); + + return 1; +} + +void* +queue_pop(queue *queue) +{ + qitem *entry; + void* item; + + enif_mutex_lock(queue->lock); + + /* Wait for an item to become available. + */ + while(queue->head == NULL) + { + enif_cond_wait(queue->cond, queue->lock); + } + + assert(queue->length >= 0 && "Invalid queue size at pop."); + + /* Woke up because queue->head != NULL + * Remove the entry and return the payload. + */ + entry = queue->head; + queue->head = entry->next; + entry->next = NULL; + + if(queue->head == NULL) + { + assert(queue->tail == entry && "Invalid queue state: Bad tail."); + queue->tail = NULL; + } + + queue->length -= 1; + + enif_mutex_unlock(queue->lock); + + item = entry->data; + enif_free(entry); + + return item; +} + +int +queue_send(queue *queue, void *item) +{ + enif_mutex_lock(queue->lock); + assert(queue->message == NULL && "Attempting to send multiple messages."); + queue->message = item; + enif_cond_signal(queue->cond); + enif_mutex_unlock(queue->lock); + return 1; +} + +void * +queue_receive(queue *queue) +{ + void *item; + + enif_mutex_lock(queue->lock); + + /* Wait for an item to become available. + */ + while(queue->message == NULL) + { + enif_cond_wait(queue->cond, queue->lock); + } + + item = queue->message; + queue->message = NULL; + + enif_mutex_unlock(queue->lock); + + return item; +} diff --git a/c_src/queue.h b/c_src/queue.h new file mode 100644 index 0000000..5ac597d --- /dev/null +++ b/c_src/queue.h @@ -0,0 +1,24 @@ +// This file is part of Emonk released under the MIT license. +// See the LICENSE file for more information. + +/* adapted by: Maas-Maarten Zeeman