1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (message_queue.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include <queues/message_queue.h>
28 #include <compat/strl.h>
29 #include <compat/posix_string.h>
31 static bool msg_queue_initialize_internal(msg_queue_t *queue, size_t size)
33 struct queue_elem **elems = (struct queue_elem**)calloc(size + 1,
34 sizeof(struct queue_elem*));
39 queue->tmp_msg = NULL;
42 queue->size = size + 1;
49 * @size : maximum size of message
51 * Creates a message queue with maximum size different messages.
53 * Returns: NULL if allocation error, pointer to a message queue
54 * if successful. Has to be freed manually.
56 msg_queue_t *msg_queue_new(size_t size)
58 msg_queue_t *queue = (msg_queue_t*)malloc(sizeof(*queue));
63 if (!msg_queue_initialize_internal(queue, size))
72 bool msg_queue_initialize(msg_queue_t *queue, size_t size)
76 return msg_queue_initialize_internal(queue, size);
81 * @queue : pointer to queue object
83 * Frees message queue..
85 void msg_queue_free(msg_queue_t *queue)
89 msg_queue_clear(queue);
94 bool msg_queue_deinitialize(msg_queue_t *queue)
98 msg_queue_clear(queue);
101 queue->tmp_msg = NULL;
109 * @queue : pointer to queue object
110 * @msg : message to add to the queue
111 * @prio : priority level of the message
112 * @duration : how many times the message can be pulled
113 * before it vanishes (E.g. show a message for
114 * 3 seconds @ 60fps = 180 duration).
116 * Push a new message onto the queue.
118 void msg_queue_push(msg_queue_t *queue, const char *msg,
119 unsigned prio, unsigned duration,
121 enum message_queue_icon icon, enum message_queue_category category)
124 struct queue_elem *new_elem = NULL;
126 if (!queue || queue->ptr >= queue->size)
129 new_elem = (struct queue_elem*)malloc(
130 sizeof(struct queue_elem));
134 new_elem->duration = duration;
135 new_elem->prio = prio;
136 new_elem->msg = msg ? strdup(msg) : NULL;
137 new_elem->title = title ? strdup(title) : NULL;
138 new_elem->icon = icon;
139 new_elem->category = category;
141 queue->elems[queue->ptr] = new_elem;
143 tmp_ptr = queue->ptr++;
147 struct queue_elem *parent = queue->elems[tmp_ptr >> 1];
148 struct queue_elem *child = queue->elems[tmp_ptr];
150 if (child->prio <= parent->prio)
153 queue->elems[tmp_ptr >> 1] = child;
154 queue->elems[tmp_ptr] = parent;
162 * @queue : pointer to queue object
164 * Clears out everything in the queue.
166 void msg_queue_clear(msg_queue_t *queue)
173 for (i = 1; i < queue->ptr; i++)
177 free(queue->elems[i]->msg);
178 free(queue->elems[i]->title);
179 free(queue->elems[i]);
180 queue->elems[i] = NULL;
184 free(queue->tmp_msg);
185 queue->tmp_msg = NULL;
190 * @queue : pointer to queue object
192 * Pulls highest priority message in queue.
194 * Returns: NULL if no message in queue, otherwise a string
195 * containing the message.
197 const char *msg_queue_pull(msg_queue_t *queue)
199 struct queue_elem *front = NULL, *last = NULL;
204 /* Nothing in queue. */
205 if (!queue || queue->ptr == 1)
208 front = (struct queue_elem*)queue->elems[1];
210 if (front->duration > 0)
213 free(queue->tmp_msg);
214 queue->tmp_msg = front->msg;
217 last = (struct queue_elem*)queue->elems[--queue->ptr];
218 queue->elems[1] = last;
224 struct queue_elem *parent = NULL;
225 struct queue_elem *child = NULL;
226 size_t switch_index = tmp_ptr;
227 bool left = (tmp_ptr * 2 <= queue->ptr)
228 && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
229 bool right = (tmp_ptr * 2 + 1 <= queue->ptr)
230 && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);
237 else if (right && !left)
238 switch_index += switch_index + 1;
241 if (queue->elems[tmp_ptr * 2]
242 >= queue->elems[tmp_ptr * 2 + 1])
245 switch_index += switch_index + 1;
248 parent = (struct queue_elem*)queue->elems[tmp_ptr];
249 child = (struct queue_elem*)queue->elems[switch_index];
250 queue->elems[tmp_ptr] = child;
251 queue->elems[switch_index] = parent;
252 tmp_ptr = switch_index;
255 return queue->tmp_msg;
260 * @queue : pointer to queue object
261 * @queue_entry : pointer to external queue entry struct
263 * Removes highest priority message from queue, copying
264 * contents into queue_entry struct.
266 * Returns: false if no messages in queue, otherwise true
268 bool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry)
270 struct queue_elem *front = NULL, *last = NULL;
273 /* Ensure arguments are valid and queue is not
275 if (!queue || queue->ptr == 1 || !queue_entry)
278 front = (struct queue_elem*)queue->elems[1];
279 last = (struct queue_elem*)queue->elems[--queue->ptr];
280 queue->elems[1] = last;
282 /* Copy element parameters */
283 queue_entry->duration = front->duration;
284 queue_entry->prio = front->prio;
285 queue_entry->icon = front->icon;
286 queue_entry->category = front->category;
287 queue_entry->msg[0] = '\0';
288 queue_entry->title[0] = '\0';
291 strlcpy(queue_entry->msg, front->msg, sizeof(queue_entry->msg));
294 strlcpy(queue_entry->title, front->title, sizeof(queue_entry->title));
303 struct queue_elem *parent = NULL;
304 struct queue_elem *child = NULL;
305 size_t switch_index = tmp_ptr;
306 bool left = (tmp_ptr * 2 <= queue->ptr)
307 && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);
308 bool right = (tmp_ptr * 2 + 1 <= queue->ptr)
309 && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);
316 else if (right && !left)
317 switch_index += switch_index + 1;
320 if (queue->elems[tmp_ptr * 2]
321 >= queue->elems[tmp_ptr * 2 + 1])
324 switch_index += switch_index + 1;
327 parent = (struct queue_elem*)queue->elems[tmp_ptr];
328 child = (struct queue_elem*)queue->elems[switch_index];
329 queue->elems[tmp_ptr] = child;
330 queue->elems[switch_index] = parent;
331 tmp_ptr = switch_index;
339 * @queue : pointer to queue object
341 * Fetches number of messages in queue.
343 * Returns: Number of messages in queue.
345 size_t msg_queue_size(msg_queue_t *queue)
347 if (!queue || queue->ptr <= 1)
350 return queue->ptr - 1;