chris@160
|
1 /**
|
chris@160
|
2 * Copyright (c) 2014, 2015, Enzien Audio Ltd.
|
chris@160
|
3 *
|
chris@160
|
4 * Permission to use, copy, modify, and/or distribute this software for any
|
chris@160
|
5 * purpose with or without fee is hereby granted, provided that the above
|
chris@160
|
6 * copyright notice and this permission notice appear in all copies.
|
chris@160
|
7 *
|
chris@160
|
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
chris@160
|
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
chris@160
|
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
chris@160
|
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
chris@160
|
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
chris@160
|
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
chris@160
|
14 * PERFORMANCE OF THIS SOFTWARE.
|
chris@160
|
15 */
|
chris@160
|
16
|
chris@160
|
17 #include "MessageQueue.h"
|
chris@160
|
18 #include "Utils.h"
|
chris@160
|
19
|
chris@160
|
20 hv_size_t mq_init(MessageQueue *q) {
|
chris@160
|
21 q->head = NULL;
|
chris@160
|
22 q->tail = NULL;
|
chris@160
|
23 q->pool = NULL;
|
chris@160
|
24 return mp_init(&q->mp, 1);
|
chris@160
|
25 }
|
chris@160
|
26
|
chris@160
|
27 void mq_initWithPoolSize(MessageQueue *q, hv_size_t poolSizeKB) {
|
chris@160
|
28 q->head = NULL;
|
chris@160
|
29 q->tail = NULL;
|
chris@160
|
30 q->pool = NULL;
|
chris@160
|
31 mp_init(&q->mp, poolSizeKB);
|
chris@160
|
32 }
|
chris@160
|
33
|
chris@160
|
34 void mq_free(MessageQueue *q) {
|
chris@160
|
35 mq_clear(q);
|
chris@160
|
36 while (q->pool != NULL) {
|
chris@160
|
37 MessageNode *n = q->pool;
|
chris@160
|
38 q->pool = q->pool->next;
|
chris@160
|
39 hv_free(n);
|
chris@160
|
40 }
|
chris@160
|
41 mp_free(&q->mp);
|
chris@160
|
42 }
|
chris@160
|
43
|
chris@160
|
44 static MessageNode *mq_getOrCreateNodeFromPool(MessageQueue *q) {
|
chris@160
|
45 if (q->pool == NULL) {
|
chris@160
|
46 // if necessary, create a new empty node
|
chris@160
|
47 q->pool = (MessageNode *) hv_malloc(sizeof(MessageNode));
|
chris@160
|
48 q->pool->next = NULL;
|
chris@160
|
49 }
|
chris@160
|
50 MessageNode *node = q->pool;
|
chris@160
|
51 q->pool = q->pool->next;
|
chris@160
|
52 return node;
|
chris@160
|
53 }
|
chris@160
|
54
|
chris@160
|
55 int mq_size(MessageQueue *q) {
|
chris@160
|
56 int size = 0;
|
chris@160
|
57 MessageNode *n = q->head;
|
chris@160
|
58 while (n != NULL) {
|
chris@160
|
59 ++size;
|
chris@160
|
60 n = n->next;
|
chris@160
|
61 }
|
chris@160
|
62 return size;
|
chris@160
|
63 }
|
chris@160
|
64
|
chris@160
|
65 HvMessage *mq_addMessage(MessageQueue *q, const HvMessage *m, int let,
|
chris@160
|
66 void (*sendMessage)(struct HvBase *, int, const HvMessage *)) {
|
chris@160
|
67 MessageNode *node = mq_getOrCreateNodeFromPool(q);
|
chris@160
|
68 node->m = mp_addMessage(&q->mp, m);
|
chris@160
|
69 node->let = let;
|
chris@160
|
70 node->sendMessage = sendMessage;
|
chris@160
|
71 node->prev = NULL;
|
chris@160
|
72 node->next = NULL;
|
chris@160
|
73
|
chris@160
|
74 if (q->tail != NULL) {
|
chris@160
|
75 // the list already contains elements
|
chris@160
|
76 q->tail->next = node;
|
chris@160
|
77 node->prev = q->tail;
|
chris@160
|
78 q->tail = node;
|
chris@160
|
79 } else {
|
chris@160
|
80 // the list is empty
|
chris@160
|
81 node->prev = NULL;
|
chris@160
|
82 q->head = node;
|
chris@160
|
83 q->tail = node;
|
chris@160
|
84 }
|
chris@160
|
85 return mq_node_getMessage(node);
|
chris@160
|
86 }
|
chris@160
|
87
|
chris@160
|
88 HvMessage *mq_addMessageByTimestamp(MessageQueue *q, HvMessage *m, int let,
|
chris@160
|
89 void (*sendMessage)(struct HvBase *, int, const HvMessage *)) {
|
chris@160
|
90 if (mq_hasMessage(q)) {
|
chris@160
|
91 MessageNode *n = mq_getOrCreateNodeFromPool(q);
|
chris@160
|
92 n->m = mp_addMessage(&q->mp, m);
|
chris@160
|
93 n->let = let;
|
chris@160
|
94 n->sendMessage = sendMessage;
|
chris@160
|
95
|
chris@160
|
96 if (msg_getTimestamp(m) < msg_getTimestamp(q->head->m)) {
|
chris@160
|
97 // the message occurs before the current head
|
chris@160
|
98 n->next = q->head;
|
chris@160
|
99 q->head->prev = n;
|
chris@160
|
100 n->prev = NULL;
|
chris@160
|
101 q->head = n;
|
chris@160
|
102 } else if (msg_getTimestamp(m) >= msg_getTimestamp(q->tail->m)) {
|
chris@160
|
103 // the message occurs after the current tail
|
chris@160
|
104 n->next = NULL;
|
chris@160
|
105 n->prev = q->tail;
|
chris@160
|
106 q->tail->next = n;
|
chris@160
|
107 q->tail = n;
|
chris@160
|
108 } else {
|
chris@160
|
109 // the message occurs somewhere between the head and tail
|
chris@160
|
110 MessageNode *node = q->head;
|
chris@160
|
111 while (node != NULL) {
|
chris@160
|
112 if (m->timestamp < msg_getTimestamp(node->next->m)) {
|
chris@160
|
113 MessageNode *r = node->next;
|
chris@160
|
114 node->next = n;
|
chris@160
|
115 n->next = r;
|
chris@160
|
116 n->prev = node;
|
chris@160
|
117 r->prev = n;
|
chris@160
|
118 break;
|
chris@160
|
119 }
|
chris@160
|
120 node = node->next;
|
chris@160
|
121 }
|
chris@160
|
122 }
|
chris@160
|
123 return n->m;
|
chris@160
|
124 } else {
|
chris@160
|
125 // add a message to the head
|
chris@160
|
126 return mq_addMessage(q, m, let, sendMessage);
|
chris@160
|
127 }
|
chris@160
|
128 }
|
chris@160
|
129
|
chris@160
|
130 void mq_pop(MessageQueue *q) {
|
chris@160
|
131 if (mq_hasMessage(q)) {
|
chris@160
|
132 MessageNode *n = q->head;
|
chris@160
|
133
|
chris@160
|
134 mp_freeMessage(&q->mp, n->m);
|
chris@160
|
135 n->m = NULL;
|
chris@160
|
136
|
chris@160
|
137 n->let = 0;
|
chris@160
|
138 n->sendMessage = NULL;
|
chris@160
|
139
|
chris@160
|
140 q->head = n->next;
|
chris@160
|
141 if (q->head == NULL) {
|
chris@160
|
142 q->tail = NULL;
|
chris@160
|
143 } else {
|
chris@160
|
144 q->head->prev = NULL;
|
chris@160
|
145 }
|
chris@160
|
146 n->next = q->pool;
|
chris@160
|
147 n->prev = NULL;
|
chris@160
|
148 q->pool = n;
|
chris@160
|
149 }
|
chris@160
|
150 }
|
chris@160
|
151
|
chris@160
|
152 void mq_removeMessage(MessageQueue *q, HvMessage *m, void (*sendMessage)(struct HvBase *, int, const HvMessage *)) {
|
chris@160
|
153 if (mq_hasMessage(q)) {
|
chris@160
|
154 if (mq_node_getMessage(q->head) == m) { // msg in head node
|
chris@160
|
155 // only remove the message if sendMessage is the same as the stored one,
|
chris@160
|
156 // if the sendMessage argument is NULL, it is not checked and will remove any matching message pointer
|
chris@160
|
157 if (sendMessage == NULL || q->head->sendMessage == sendMessage) {
|
chris@160
|
158 mq_pop(q);
|
chris@160
|
159 }
|
chris@160
|
160 } else {
|
chris@160
|
161 MessageNode *prevNode = q->head;
|
chris@160
|
162 MessageNode *currNode = q->head->next;
|
chris@160
|
163 while ((currNode != NULL) && (currNode->m != m)) {
|
chris@160
|
164 prevNode = currNode;
|
chris@160
|
165 currNode = currNode->next;
|
chris@160
|
166 }
|
chris@160
|
167 if (currNode != NULL) {
|
chris@160
|
168 if (sendMessage == NULL || currNode->sendMessage == sendMessage) {
|
chris@160
|
169 mp_freeMessage(&q->mp, m);
|
chris@160
|
170 currNode->m = NULL;
|
chris@160
|
171 currNode->let = 0;
|
chris@160
|
172 currNode->sendMessage = NULL;
|
chris@160
|
173 if (currNode == q->tail) { // msg in tail node
|
chris@160
|
174 prevNode->next = NULL;
|
chris@160
|
175 q->tail = prevNode;
|
chris@160
|
176 } else { // msg in middle node
|
chris@160
|
177 prevNode->next = currNode->next;
|
chris@160
|
178 currNode->next->prev = prevNode;
|
chris@160
|
179 }
|
chris@160
|
180 currNode->next = (q->pool == NULL) ? NULL : q->pool;
|
chris@160
|
181 currNode->prev = NULL;
|
chris@160
|
182 q->pool = currNode;
|
chris@160
|
183 }
|
chris@160
|
184 }
|
chris@160
|
185 }
|
chris@160
|
186 }
|
chris@160
|
187 }
|
chris@160
|
188
|
chris@160
|
189 void mq_clear(MessageQueue *q) {
|
chris@160
|
190 while (mq_hasMessage(q)) {
|
chris@160
|
191 mq_pop(q);
|
chris@160
|
192 }
|
chris@160
|
193 }
|
chris@160
|
194
|
chris@160
|
195 void mq_clearAfter(MessageQueue *q, const double timestamp) {
|
chris@160
|
196 MessageNode *n = q->tail;
|
chris@160
|
197 while (n != NULL && timestamp <= msg_getTimestamp(n->m)) {
|
chris@160
|
198 // free the node's message
|
chris@160
|
199 mp_freeMessage(&q->mp, n->m);
|
chris@160
|
200 n->m = NULL;
|
chris@160
|
201 n->let = 0;
|
chris@160
|
202 n->sendMessage = NULL;
|
chris@160
|
203
|
chris@160
|
204 // the tail points at the previous node
|
chris@160
|
205 q->tail = n->prev;
|
chris@160
|
206
|
chris@160
|
207 // put the node back in the pool
|
chris@160
|
208 n->next = q->pool;
|
chris@160
|
209 n->prev = NULL;
|
chris@160
|
210 if (q->pool != NULL) q->pool->prev = n;
|
chris@160
|
211 q->pool = n;
|
chris@160
|
212
|
chris@160
|
213 // update the tail node
|
chris@160
|
214 n = q->tail;
|
chris@160
|
215 }
|
chris@160
|
216
|
chris@160
|
217 if (q->tail == NULL) q->head = NULL;
|
chris@160
|
218 }
|