Mercurial > hg > beaglert
diff projects/heavy/circularBuffer/MessageQueue.c @ 163:20b52283c7b4 heavy-updated
- added circular buffer pd/heavy example (works but process needs to be killed manually if launched via ssh?)
author | chnrx <chris.heinrichs@gmail.com> |
---|---|
date | Thu, 12 Nov 2015 15:55:30 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/projects/heavy/circularBuffer/MessageQueue.c Thu Nov 12 15:55:30 2015 +0000 @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2014, 2015, Enzien Audio Ltd. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "MessageQueue.h" +#include "Utils.h" + +hv_size_t mq_init(MessageQueue *q) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + return mp_init(&q->mp, 1); +} + +void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB) { + q->head = NULL; + q->tail = NULL; + q->pool = NULL; + mp_init(&q->mp, poolSizeKB); +} + +void mq_free(MessageQueue *q) { + mq_clear(q); + while (q->pool != NULL) { + MessageNode *n = q->pool; + q->pool = q->pool->next; + hv_free(n); + } + mp_free(&q->mp); +} + +static MessageNode *mq_getOrCreateNodeFromPool(MessageQueue *q) { + if (q->pool == NULL) { + // if necessary, create a new empty node + q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode)); + q->pool->next = NULL; + } + MessageNode *node = q->pool; + q->pool = q->pool->next; + return node; +} + +int mq_size(MessageQueue *q) { + int size = 0; + MessageNode *n = q->head; + while (n != NULL) { + ++size; + n = n->next; + } + return size; +} + +HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + MessageNode *node = mq_getOrCreateNodeFromPool(q); + node->m = mp_addMessage(&q->mp, m); + node->let = let; + node->sendMessage = sendMessage; + node->prev = NULL; + node->next = NULL; + + if (q->tail != NULL) { + // the list already contains elements + q->tail->next = node; + node->prev = q->tail; + q->tail = node; + } else { + // the list is empty + node->prev = NULL; + q->head = node; + q->tail = node; + } + return mq_node_getMessage(node); +} + +HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let, + void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + MessageNode *n = mq_getOrCreateNodeFromPool(q); + n->m = mp_addMessage(&q->mp, m); + n->let = let; + n->sendMessage = sendMessage; + + if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) { + // the message occurs before the current head + n->next = q->head; + q->head->prev = n; + n->prev = NULL; + q->head = n; + } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) { + // the message occurs after the current tail + n->next = NULL; + n->prev = q->tail; + q->tail->next = n; + q->tail = n; + } else { + // the message occurs somewhere between the head and tail + MessageNode *node = q->head; + while (node != NULL) { + if (m->timestamp < msg_getTimestamp(node->next->m)) { + MessageNode *r = node->next; + node->next = n; + n->next = r; + n->prev = node; + r->prev = n; + break; + } + node = node->next; + } + } + return n->m; + } else { + // add a message to the head + return mq_addMessage(q, m, let, sendMessage); + } +} + +void mq_pop(MessageQueue *q) { + if (mq_hasMessage(q)) { + MessageNode *n = q->head; + + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + + n->let = 0; + n->sendMessage = NULL; + + q->head = n->next; + if (q->head == NULL) { + q->tail = NULL; + } else { + q->head->prev = NULL; + } + n->next = q->pool; + n->prev = NULL; + q->pool = n; + } +} + +void mq_removeMessage(MessageQueue *q, HvMessage *m, void (*sendMessage)(struct HvBase *, int, const HvMessage *)) { + if (mq_hasMessage(q)) { + if (mq_node_getMessage(q->head) == m) { // msg in head node + // only remove the message if sendMessage is the same as the stored one, + // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer + if (sendMessage == NULL || q->head->sendMessage == sendMessage) { + mq_pop(q); + } + } else { + MessageNode *prevNode = q->head; + MessageNode *currNode = q->head->next; + while ((currNode != NULL) && (currNode->m != m)) { + prevNode = currNode; + currNode = currNode->next; + } + if (currNode != NULL) { + if (sendMessage == NULL || currNode->sendMessage == sendMessage) { + mp_freeMessage(&q->mp, m); + currNode->m = NULL; + currNode->let = 0; + currNode->sendMessage = NULL; + if (currNode == q->tail) { // msg in tail node + prevNode->next = NULL; + q->tail = prevNode; + } else { // msg in middle node + prevNode->next = currNode->next; + currNode->next->prev = prevNode; + } + currNode->next = (q->pool == NULL) ? NULL : q->pool; + currNode->prev = NULL; + q->pool = currNode; + } + } + } + } +} + +void mq_clear(MessageQueue *q) { + while (mq_hasMessage(q)) { + mq_pop(q); + } +} + +void mq_clearAfter(MessageQueue *q, const double timestamp) { + MessageNode *n = q->tail; + while (n != NULL && timestamp <= msg_getTimestamp(n->m)) { + // free the node's message + mp_freeMessage(&q->mp, n->m); + n->m = NULL; + n->let = 0; + n->sendMessage = NULL; + + // the tail points at the previous node + q->tail = n->prev; + + // put the node back in the pool + n->next = q->pool; + n->prev = NULL; + if (q->pool != NULL) q->pool->prev = n; + q->pool = n; + + // update the tail node + n = q->tail; + } + + if (q->tail == NULL) q->head = NULL; +}