1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * GAsyncQueue: asynchronous queue implementation, based on GQueue.
5 * Copyright (C) 2000 Sebastian Wilhelmi; University of Karlsruhe
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24 * MT safe
25 */
26
27 #include "config.h"
28
29 #include "gasyncqueue.h"
30 #include "gasyncqueueprivate.h"
31
32 #include "gmain.h"
33 #include "gmem.h"
34 #include "gqueue.h"
35 #include "gtestutils.h"
36 #include "gtimer.h"
37 #include "gthread.h"
38 #include "deprecated/gthread.h"
39
40 /**
41 * GAsyncQueue:
42 *
43 * An opaque data structure which represents an asynchronous queue.
44 *
45 * It should only be accessed through the `g_async_queue_*` functions.
46 */
47 struct _GAsyncQueue
48 {
49 GMutex mutex;
50 GCond cond;
51 GQueue queue;
52 GDestroyNotify item_free_func;
53 guint waiting_threads;
54 gint ref_count;
55 };
56
57 typedef struct
58 {
59 GCompareDataFunc func;
60 gpointer user_data;
61 } SortData;
62
63 /**
64 * g_async_queue_new: (constructor)
65 *
66 * Creates a new asynchronous queue.
67 *
68 * Returns: (transfer full): a new #GAsyncQueue. Free with g_async_queue_unref()
69 */
70 GAsyncQueue *
71 g_async_queue_new (void)
72 {
73 return g_async_queue_new_full (NULL);
74 }
75
76 /**
77 * g_async_queue_new_full: (constructor)
78 * @item_free_func: (nullable): function to free queue elements
79 *
80 * Creates a new asynchronous queue and sets up a destroy notify
81 * function that is used to free any remaining queue items when
82 * the queue is destroyed after the final unref.
83 *
84 * Returns: (transfer full): a new #GAsyncQueue. Free with g_async_queue_unref()
85 *
86 * Since: 2.16
87 */
88 GAsyncQueue *
89 g_async_queue_new_full (GDestroyNotify item_free_func)
90 {
91 GAsyncQueue *queue;
92
93 queue = g_new (GAsyncQueue, 1);
94 g_mutex_init (&queue->mutex);
95 g_cond_init (&queue->cond);
96 g_queue_init (&queue->queue);
97 queue->waiting_threads = 0;
98 queue->ref_count = 1;
99 queue->item_free_func = item_free_func;
100
101 return queue;
102 }
103
104 /**
105 * g_async_queue_ref:
106 * @queue: a #GAsyncQueue
107 *
108 * Increases the reference count of the asynchronous @queue by 1.
109 * You do not need to hold the lock to call this function.
110 *
111 * Returns: (transfer full): the @queue that was passed in (since 2.6)
112 */
113 GAsyncQueue *
114 g_async_queue_ref (GAsyncQueue *queue)
115 {
116 g_return_val_if_fail (queue, NULL);
117
118 g_atomic_int_inc (&queue->ref_count);
119
120 return queue;
121 }
122
123 /**
124 * g_async_queue_ref_unlocked:
125 * @queue: a #GAsyncQueue
126 *
127 * Increases the reference count of the asynchronous @queue by 1.
128 *
129 * Deprecated: 2.8: Reference counting is done atomically.
130 * so g_async_queue_ref() can be used regardless of the @queue's
131 * lock.
132 */
133 void
134 g_async_queue_ref_unlocked (GAsyncQueue *queue)
135 {
136 g_return_if_fail (queue);
137
138 g_atomic_int_inc (&queue->ref_count);
139 }
140
141 /**
142 * g_async_queue_unref_and_unlock:
143 * @queue: a #GAsyncQueue
144 *
145 * Decreases the reference count of the asynchronous @queue by 1
146 * and releases the lock. This function must be called while holding
147 * the @queue's lock. If the reference count went to 0, the @queue
148 * will be destroyed and the memory allocated will be freed.
149 *
150 * Deprecated: 2.8: Reference counting is done atomically.
151 * so g_async_queue_unref() can be used regardless of the @queue's
152 * lock.
153 */
154 void
155 g_async_queue_unref_and_unlock (GAsyncQueue *queue)
156 {
157 g_return_if_fail (queue);
158
159 g_mutex_unlock (&queue->mutex);
160 g_async_queue_unref (queue);
161 }
162
163 /**
164 * g_async_queue_unref:
165 * @queue: (transfer full): a #GAsyncQueue.
166 *
167 * Decreases the reference count of the asynchronous @queue by 1.
168 *
169 * If the reference count went to 0, the @queue will be destroyed
170 * and the memory allocated will be freed. So you are not allowed
171 * to use the @queue afterwards, as it might have disappeared.
172 * You do not need to hold the lock to call this function.
173 */
174 void
175 g_async_queue_unref (GAsyncQueue *queue)
176 {
177 g_return_if_fail (queue);
178
179 if (g_atomic_int_dec_and_test (&queue->ref_count))
180 {
181 g_return_if_fail (queue->waiting_threads == 0);
182 g_mutex_clear (&queue->mutex);
183 g_cond_clear (&queue->cond);
184 if (queue->item_free_func)
185 g_queue_foreach (&queue->queue, (GFunc) queue->item_free_func, NULL);
186 g_queue_clear (&queue->queue);
187 g_free (queue);
188 }
189 }
190
191 /**
192 * g_async_queue_lock:
193 * @queue: a #GAsyncQueue
194 *
195 * Acquires the @queue's lock. If another thread is already
196 * holding the lock, this call will block until the lock
197 * becomes available.
198 *
199 * Call g_async_queue_unlock() to drop the lock again.
200 *
201 * While holding the lock, you can only call the
202 * g_async_queue_*_unlocked() functions on @queue. Otherwise,
203 * deadlock may occur.
204 */
205 void
206 g_async_queue_lock (GAsyncQueue *queue)
207 {
208 g_return_if_fail (queue);
209
210 g_mutex_lock (&queue->mutex);
211 }
212
213 /**
214 * g_async_queue_unlock:
215 * @queue: a #GAsyncQueue
216 *
217 * Releases the queue's lock.
218 *
219 * Calling this function when you have not acquired
220 * the with g_async_queue_lock() leads to undefined
221 * behaviour.
222 */
223 void
224 g_async_queue_unlock (GAsyncQueue *queue)
225 {
226 g_return_if_fail (queue);
227
228 g_mutex_unlock (&queue->mutex);
229 }
230
231 /**
232 * g_async_queue_push:
233 * @queue: a #GAsyncQueue
234 * @data: (not nullable): data to push onto the @queue
235 *
236 * Pushes the @data into the @queue.
237 *
238 * The @data parameter must not be %NULL.
239 */
240 void
241 g_async_queue_push (GAsyncQueue *queue,
242 gpointer data)
243 {
244 g_return_if_fail (queue);
245 g_return_if_fail (data);
246
247 g_mutex_lock (&queue->mutex);
248 g_async_queue_push_unlocked (queue, data);
249 g_mutex_unlock (&queue->mutex);
250 }
251
252 /**
253 * g_async_queue_push_unlocked:
254 * @queue: a #GAsyncQueue
255 * @data: (not nullable): data to push onto the @queue
256 *
257 * Pushes the @data into the @queue.
258 *
259 * The @data parameter must not be %NULL.
260 *
261 * This function must be called while holding the @queue's lock.
262 */
263 void
264 g_async_queue_push_unlocked (GAsyncQueue *queue,
265 gpointer data)
266 {
267 g_return_if_fail (queue);
268 g_return_if_fail (data);
269
270 g_queue_push_head (&queue->queue, data);
271 if (queue->waiting_threads > 0)
272 g_cond_signal (&queue->cond);
273 }
274
275 /**
276 * g_async_queue_push_sorted:
277 * @queue: a #GAsyncQueue
278 * @data: (not nullable): the @data to push into the @queue
279 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
280 * @user_data: user data passed to @func.
281 *
282 * Inserts @data into @queue using @func to determine the new
283 * position.
284 *
285 * This function requires that the @queue is sorted before pushing on
286 * new elements, see g_async_queue_sort().
287 *
288 * This function will lock @queue before it sorts the queue and unlock
289 * it when it is finished.
290 *
291 * For an example of @func see g_async_queue_sort().
292 *
293 * Since: 2.10
294 */
295 void
296 g_async_queue_push_sorted (GAsyncQueue *queue,
297 gpointer data,
298 GCompareDataFunc func,
299 gpointer user_data)
300 {
301 g_return_if_fail (queue != NULL);
302
303 g_mutex_lock (&queue->mutex);
304 g_async_queue_push_sorted_unlocked (queue, data, func, user_data);
305 g_mutex_unlock (&queue->mutex);
306 }
307
308 static gint
309 g_async_queue_invert_compare (gpointer v1,
310 gpointer v2,
311 SortData *sd)
312 {
313 return -sd->func (v1, v2, sd->user_data);
314 }
315
316 /**
317 * g_async_queue_push_sorted_unlocked:
318 * @queue: a #GAsyncQueue
319 * @data: the data to push into the @queue
320 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
321 * @user_data: user data passed to @func.
322 *
323 * Inserts @data into @queue using @func to determine the new
324 * position.
325 *
326 * The sort function @func is passed two elements of the @queue.
327 * It should return 0 if they are equal, a negative value if the
328 * first element should be higher in the @queue or a positive value
329 * if the first element should be lower in the @queue than the second
330 * element.
331 *
332 * This function requires that the @queue is sorted before pushing on
333 * new elements, see g_async_queue_sort().
334 *
335 * This function must be called while holding the @queue's lock.
336 *
337 * For an example of @func see g_async_queue_sort().
338 *
339 * Since: 2.10
340 */
341 void
342 g_async_queue_push_sorted_unlocked (GAsyncQueue *queue,
343 gpointer data,
344 GCompareDataFunc func,
345 gpointer user_data)
346 {
347 SortData sd;
348
349 g_return_if_fail (queue != NULL);
350
351 sd.func = func;
352 sd.user_data = user_data;
353
354 g_queue_insert_sorted (&queue->queue,
355 data,
356 (GCompareDataFunc)g_async_queue_invert_compare,
357 &sd);
358 if (queue->waiting_threads > 0)
359 g_cond_signal (&queue->cond);
360 }
361
362 static gpointer
363 g_async_queue_pop_intern_unlocked (GAsyncQueue *queue,
364 gboolean wait,
365 gint64 end_time)
366 {
367 gpointer retval;
368
369 if (!g_queue_peek_tail_link (&queue->queue) && wait)
370 {
371 queue->waiting_threads++;
372 while (!g_queue_peek_tail_link (&queue->queue))
373 {
374 if (end_time == -1)
375 g_cond_wait (&queue->cond, &queue->mutex);
376 else
377 {
378 if (!g_cond_wait_until (&queue->cond, &queue->mutex, end_time))
379 break;
380 }
381 }
382 queue->waiting_threads--;
383 }
384
385 retval = g_queue_pop_tail (&queue->queue);
386
387 g_assert (retval || !wait || end_time > 0);
388
389 return retval;
390 }
391
392 /**
393 * g_async_queue_pop:
394 * @queue: a #GAsyncQueue
395 *
396 * Pops data from the @queue. If @queue is empty, this function
397 * blocks until data becomes available.
398 *
399 * Returns: data from the queue
400 */
401 gpointer
402 g_async_queue_pop (GAsyncQueue *queue)
403 {
404 gpointer retval;
405
406 g_return_val_if_fail (queue, NULL);
407
408 g_mutex_lock (&queue->mutex);
409 retval = g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
410 g_mutex_unlock (&queue->mutex);
411
412 return retval;
413 }
414
415 /**
416 * g_async_queue_pop_unlocked:
417 * @queue: a #GAsyncQueue
418 *
419 * Pops data from the @queue. If @queue is empty, this function
420 * blocks until data becomes available.
421 *
422 * This function must be called while holding the @queue's lock.
423 *
424 * Returns: data from the queue.
425 */
426 gpointer
427 g_async_queue_pop_unlocked (GAsyncQueue *queue)
428 {
429 g_return_val_if_fail (queue, NULL);
430
431 return g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
432 }
433
434 /**
435 * g_async_queue_try_pop:
436 * @queue: a #GAsyncQueue
437 *
438 * Tries to pop data from the @queue. If no data is available,
439 * %NULL is returned.
440 *
441 * Returns: (nullable): data from the queue or %NULL, when no data is
442 * available immediately.
443 */
444 gpointer
445 g_async_queue_try_pop (GAsyncQueue *queue)
446 {
447 gpointer retval;
448
449 g_return_val_if_fail (queue, NULL);
450
451 g_mutex_lock (&queue->mutex);
452 retval = g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
453 g_mutex_unlock (&queue->mutex);
454
455 return retval;
456 }
457
458 /**
459 * g_async_queue_try_pop_unlocked:
460 * @queue: a #GAsyncQueue
461 *
462 * Tries to pop data from the @queue. If no data is available,
463 * %NULL is returned.
464 *
465 * This function must be called while holding the @queue's lock.
466 *
467 * Returns: (nullable): data from the queue or %NULL, when no data is
468 * available immediately.
469 */
470 gpointer
471 g_async_queue_try_pop_unlocked (GAsyncQueue *queue)
472 {
473 g_return_val_if_fail (queue, NULL);
474
475 return g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
476 }
477
478 /**
479 * g_async_queue_timeout_pop:
480 * @queue: a #GAsyncQueue
481 * @timeout: the number of microseconds to wait
482 *
483 * Pops data from the @queue. If the queue is empty, blocks for
484 * @timeout microseconds, or until data becomes available.
485 *
486 * If no data is received before the timeout, %NULL is returned.
487 *
488 * Returns: (nullable): data from the queue or %NULL, when no data is
489 * received before the timeout.
490 */
491 gpointer
492 g_async_queue_timeout_pop (GAsyncQueue *queue,
493 guint64 timeout)
494 {
495 gint64 end_time = g_get_monotonic_time () + timeout;
496 gpointer retval;
497
498 g_return_val_if_fail (queue != NULL, NULL);
499
500 g_mutex_lock (&queue->mutex);
501 retval = g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
502 g_mutex_unlock (&queue->mutex);
503
504 return retval;
505 }
506
507 /**
508 * g_async_queue_timeout_pop_unlocked:
509 * @queue: a #GAsyncQueue
510 * @timeout: the number of microseconds to wait
511 *
512 * Pops data from the @queue. If the queue is empty, blocks for
513 * @timeout microseconds, or until data becomes available.
514 *
515 * If no data is received before the timeout, %NULL is returned.
516 *
517 * This function must be called while holding the @queue's lock.
518 *
519 * Returns: (nullable): data from the queue or %NULL, when no data is
520 * received before the timeout.
521 */
522 gpointer
523 g_async_queue_timeout_pop_unlocked (GAsyncQueue *queue,
524 guint64 timeout)
525 {
526 gint64 end_time = g_get_monotonic_time () + timeout;
527
528 g_return_val_if_fail (queue != NULL, NULL);
529
530 return g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
531 }
532
533 /**
534 * g_async_queue_timed_pop:
535 * @queue: a #GAsyncQueue
536 * @end_time: a #GTimeVal, determining the final time
537 *
538 * Pops data from the @queue. If the queue is empty, blocks until
539 * @end_time or until data becomes available.
540 *
541 * If no data is received before @end_time, %NULL is returned.
542 *
543 * To easily calculate @end_time, a combination of g_get_real_time()
544 * and g_time_val_add() can be used.
545 *
546 * Returns: (nullable): data from the queue or %NULL, when no data is
547 * received before @end_time.
548 *
549 * Deprecated: use g_async_queue_timeout_pop().
550 */
551 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
552 gpointer
553 g_async_queue_timed_pop (GAsyncQueue *queue,
554 GTimeVal *end_time)
555 {
556 gint64 m_end_time;
557 gpointer retval;
558
559 g_return_val_if_fail (queue, NULL);
560
561 if (end_time != NULL)
562 {
563 m_end_time = g_get_monotonic_time () +
564 ((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
565 }
566 else
567 m_end_time = -1;
568
569 g_mutex_lock (&queue->mutex);
570 retval = g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
571 g_mutex_unlock (&queue->mutex);
572
573 return retval;
574 }
575 G_GNUC_END_IGNORE_DEPRECATIONS
576
577 /**
578 * g_async_queue_timed_pop_unlocked:
579 * @queue: a #GAsyncQueue
580 * @end_time: a #GTimeVal, determining the final time
581 *
582 * Pops data from the @queue. If the queue is empty, blocks until
583 * @end_time or until data becomes available.
584 *
585 * If no data is received before @end_time, %NULL is returned.
586 *
587 * To easily calculate @end_time, a combination of g_get_real_time()
588 * and g_time_val_add() can be used.
589 *
590 * This function must be called while holding the @queue's lock.
591 *
592 * Returns: (nullable): data from the queue or %NULL, when no data is
593 * received before @end_time.
594 *
595 * Deprecated: use g_async_queue_timeout_pop_unlocked().
596 */
597 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
598 gpointer
599 g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
600 GTimeVal *end_time)
601 {
602 gint64 m_end_time;
603
604 g_return_val_if_fail (queue, NULL);
605
606 if (end_time != NULL)
607 {
608 m_end_time = g_get_monotonic_time () +
609 ((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
610 }
611 else
612 m_end_time = -1;
613
614 return g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
615 }
616 G_GNUC_END_IGNORE_DEPRECATIONS
617
618 /**
619 * g_async_queue_length:
620 * @queue: a #GAsyncQueue.
621 *
622 * Returns the length of the queue.
623 *
624 * Actually this function returns the number of data items in
625 * the queue minus the number of waiting threads, so a negative
626 * value means waiting threads, and a positive value means available
627 * entries in the @queue. A return value of 0 could mean n entries
628 * in the queue and n threads waiting. This can happen due to locking
629 * of the queue or due to scheduling.
630 *
631 * Returns: the length of the @queue
632 */
633 gint
634 g_async_queue_length (GAsyncQueue *queue)
635 {
636 gint retval;
637
638 g_return_val_if_fail (queue, 0);
639
640 g_mutex_lock (&queue->mutex);
641 retval = queue->queue.length - queue->waiting_threads;
642 g_mutex_unlock (&queue->mutex);
643
644 return retval;
645 }
646
647 /**
648 * g_async_queue_length_unlocked:
649 * @queue: a #GAsyncQueue
650 *
651 * Returns the length of the queue.
652 *
653 * Actually this function returns the number of data items in
654 * the queue minus the number of waiting threads, so a negative
655 * value means waiting threads, and a positive value means available
656 * entries in the @queue. A return value of 0 could mean n entries
657 * in the queue and n threads waiting. This can happen due to locking
658 * of the queue or due to scheduling.
659 *
660 * This function must be called while holding the @queue's lock.
661 *
662 * Returns: the length of the @queue.
663 */
664 gint
665 g_async_queue_length_unlocked (GAsyncQueue *queue)
666 {
667 g_return_val_if_fail (queue, 0);
668
669 return queue->queue.length - queue->waiting_threads;
670 }
671
672 /**
673 * g_async_queue_sort:
674 * @queue: a #GAsyncQueue
675 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
676 * @user_data: user data passed to @func
677 *
678 * Sorts @queue using @func.
679 *
680 * The sort function @func is passed two elements of the @queue.
681 * It should return 0 if they are equal, a negative value if the
682 * first element should be higher in the @queue or a positive value
683 * if the first element should be lower in the @queue than the second
684 * element.
685 *
686 * This function will lock @queue before it sorts the queue and unlock
687 * it when it is finished.
688 *
689 * If you were sorting a list of priority numbers to make sure the
690 * lowest priority would be at the top of the queue, you could use:
691 * |[<!-- language="C" -->
692 * gint32 id1;
693 * gint32 id2;
694 *
695 * id1 = GPOINTER_TO_INT (element1);
696 * id2 = GPOINTER_TO_INT (element2);
697 *
698 * return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
699 * ]|
700 *
701 * Since: 2.10
702 */
703 void
704 g_async_queue_sort (GAsyncQueue *queue,
705 GCompareDataFunc func,
706 gpointer user_data)
707 {
708 g_return_if_fail (queue != NULL);
709 g_return_if_fail (func != NULL);
710
711 g_mutex_lock (&queue->mutex);
712 g_async_queue_sort_unlocked (queue, func, user_data);
713 g_mutex_unlock (&queue->mutex);
714 }
715
716 /**
717 * g_async_queue_sort_unlocked:
718 * @queue: a #GAsyncQueue
719 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
720 * @user_data: user data passed to @func
721 *
722 * Sorts @queue using @func.
723 *
724 * The sort function @func is passed two elements of the @queue.
725 * It should return 0 if they are equal, a negative value if the
726 * first element should be higher in the @queue or a positive value
727 * if the first element should be lower in the @queue than the second
728 * element.
729 *
730 * This function must be called while holding the @queue's lock.
731 *
732 * Since: 2.10
733 */
734 void
735 g_async_queue_sort_unlocked (GAsyncQueue *queue,
736 GCompareDataFunc func,
737 gpointer user_data)
738 {
739 SortData sd;
740
741 g_return_if_fail (queue != NULL);
742 g_return_if_fail (func != NULL);
743
744 sd.func = func;
745 sd.user_data = user_data;
746
747 g_queue_sort (&queue->queue,
748 (GCompareDataFunc)g_async_queue_invert_compare,
749 &sd);
750 }
751
752 /**
753 * g_async_queue_remove:
754 * @queue: a #GAsyncQueue
755 * @item: (not nullable): the data to remove from the @queue
756 *
757 * Remove an item from the queue.
758 *
759 * Returns: %TRUE if the item was removed
760 *
761 * Since: 2.46
762 */
763 gboolean
764 g_async_queue_remove (GAsyncQueue *queue,
765 gpointer item)
766 {
767 gboolean ret;
768
769 g_return_val_if_fail (queue != NULL, FALSE);
770 g_return_val_if_fail (item != NULL, FALSE);
771
772 g_mutex_lock (&queue->mutex);
773 ret = g_async_queue_remove_unlocked (queue, item);
774 g_mutex_unlock (&queue->mutex);
775
776 return ret;
777 }
778
779 /**
780 * g_async_queue_remove_unlocked:
781 * @queue: a #GAsyncQueue
782 * @item: the data to remove from the @queue
783 *
784 * Remove an item from the queue.
785 *
786 * This function must be called while holding the @queue's lock.
787 *
788 * Returns: %TRUE if the item was removed
789 *
790 * Since: 2.46
791 */
792 gboolean
793 g_async_queue_remove_unlocked (GAsyncQueue *queue,
794 gpointer item)
795 {
796 g_return_val_if_fail (queue != NULL, FALSE);
797 g_return_val_if_fail (item != NULL, FALSE);
798
799 return g_queue_remove (&queue->queue, item);
800 }
801
802 /**
803 * g_async_queue_push_front:
804 * @queue: a #GAsyncQueue
805 * @item: (not nullable): data to push into the @queue
806 *
807 * Pushes the @item into the @queue. @item must not be %NULL.
808 * In contrast to g_async_queue_push(), this function
809 * pushes the new item ahead of the items already in the queue,
810 * so that it will be the next one to be popped off the queue.
811 *
812 * Since: 2.46
813 */
814 void
815 g_async_queue_push_front (GAsyncQueue *queue,
816 gpointer item)
817 {
818 g_return_if_fail (queue != NULL);
819 g_return_if_fail (item != NULL);
820
821 g_mutex_lock (&queue->mutex);
822 g_async_queue_push_front_unlocked (queue, item);
823 g_mutex_unlock (&queue->mutex);
824 }
825
826 /**
827 * g_async_queue_push_front_unlocked:
828 * @queue: a #GAsyncQueue
829 * @item: (not nullable): data to push into the @queue
830 *
831 * Pushes the @item into the @queue. @item must not be %NULL.
832 * In contrast to g_async_queue_push_unlocked(), this function
833 * pushes the new item ahead of the items already in the queue,
834 * so that it will be the next one to be popped off the queue.
835 *
836 * This function must be called while holding the @queue's lock.
837 *
838 * Since: 2.46
839 */
840 void
841 g_async_queue_push_front_unlocked (GAsyncQueue *queue,
842 gpointer item)
843 {
844 g_return_if_fail (queue != NULL);
845 g_return_if_fail (item != NULL);
846
847 g_queue_push_tail (&queue->queue, item);
848 if (queue->waiting_threads > 0)
849 g_cond_signal (&queue->cond);
850 }
851
852 /*
853 * Private API
854 */
855
856 GMutex *
857 _g_async_queue_get_mutex (GAsyncQueue *queue)
858 {
859 g_return_val_if_fail (queue, NULL);
860
861 return &queue->mutex;
862 }