Coverage Report

Created: 2026-10-14 08:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib-2.88.3/glib/gasyncqueue.c
Line
Count
Source
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: (copy-func g_async_queue_ref) (free-func g_async_queue_unref)
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
0
{
73
0
  return g_async_queue_new_full (NULL);
74
0
}
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
0
{
91
0
  GAsyncQueue *queue;
92
93
0
  queue = g_new (GAsyncQueue, 1);
94
0
  g_mutex_init (&queue->mutex);
95
0
  g_cond_init (&queue->cond);
96
0
  g_queue_init (&queue->queue);
97
0
  queue->waiting_threads = 0;
98
0
  queue->ref_count = 1;
99
0
  queue->item_free_func = item_free_func;
100
101
0
  return queue;
102
0
}
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
0
{
116
0
  g_return_val_if_fail (queue, NULL);
117
118
0
  g_atomic_int_inc (&queue->ref_count);
119
120
0
  return queue;
121
0
}
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
0
{
136
0
  g_return_if_fail (queue);
137
138
0
  g_atomic_int_inc (&queue->ref_count);
139
0
}
140
141
/**
142
 * g_async_queue_unref_and_unlock:
143
 * @queue: (transfer full): 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
0
{
157
0
  g_return_if_fail (queue);
158
159
0
  g_mutex_unlock (&queue->mutex);
160
0
  g_async_queue_unref (queue);
161
0
}
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
0
{
177
0
  g_return_if_fail (queue);
178
179
0
  if (g_atomic_int_dec_and_test (&queue->ref_count))
180
0
    {
181
0
      g_return_if_fail (queue->waiting_threads == 0);
182
0
      g_mutex_clear (&queue->mutex);
183
0
      g_cond_clear (&queue->cond);
184
0
      if (queue->item_free_func)
185
0
        g_queue_foreach (&queue->queue, (GFunc) queue->item_free_func, NULL);
186
0
      g_queue_clear (&queue->queue);
187
0
      g_free (queue);
188
0
    }
189
0
}
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
0
{
208
0
  g_return_if_fail (queue);
209
210
0
  g_mutex_lock (&queue->mutex);
211
0
}
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
0
{
226
0
  g_return_if_fail (queue);
227
228
0
  g_mutex_unlock (&queue->mutex);
229
0
}
230
231
/**
232
 * g_async_queue_push:
233
 * @queue: a #GAsyncQueue
234
 * @data: (not nullable) (transfer full): 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
0
{
244
0
  g_return_if_fail (queue);
245
0
  g_return_if_fail (data);
246
247
0
  g_mutex_lock (&queue->mutex);
248
0
  g_async_queue_push_unlocked (queue, data);
249
0
  g_mutex_unlock (&queue->mutex);
250
0
}
251
252
/**
253
 * g_async_queue_push_unlocked:
254
 * @queue: a #GAsyncQueue
255
 * @data: (not nullable) (transfer full): 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
0
{
267
0
  g_return_if_fail (queue);
268
0
  g_return_if_fail (data);
269
270
0
  g_queue_push_head (&queue->queue, data);
271
0
  if (queue->waiting_threads > 0)
272
0
    g_cond_signal (&queue->cond);
273
0
}
274
275
/**
276
 * g_async_queue_push_sorted:
277
 * @queue: a #GAsyncQueue
278
 * @data: (not nullable) (transfer full): 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
0
{
301
0
  g_return_if_fail (queue != NULL);
302
303
0
  g_mutex_lock (&queue->mutex);
304
0
  g_async_queue_push_sorted_unlocked (queue, data, func, user_data);
305
0
  g_mutex_unlock (&queue->mutex);
306
0
}
307
308
static gint
309
g_async_queue_invert_compare (gpointer  v1,
310
                              gpointer  v2,
311
                              SortData *sd)
312
0
{
313
0
  return -sd->func (v1, v2, sd->user_data);
314
0
}
315
316
/**
317
 * g_async_queue_push_sorted_unlocked:
318
 * @queue: a #GAsyncQueue
319
 * @data: (not nullable) (transfer full): 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
0
{
347
0
  SortData sd;
348
349
0
  g_return_if_fail (queue != NULL);
350
0
  g_return_if_fail (data != NULL);
351
352
0
  sd.func = func;
353
0
  sd.user_data = user_data;
354
355
0
  g_queue_insert_sorted (&queue->queue,
356
0
                         data,
357
0
                         (GCompareDataFunc)g_async_queue_invert_compare,
358
0
                         &sd);
359
0
  if (queue->waiting_threads > 0)
360
0
    g_cond_signal (&queue->cond);
361
0
}
362
363
static gpointer
364
g_async_queue_pop_intern_unlocked (GAsyncQueue *queue,
365
                                   gboolean     wait,
366
                                   gint64       end_time)
367
0
{
368
0
  gpointer retval;
369
370
0
  if (!g_queue_peek_tail_link (&queue->queue) && wait)
371
0
    {
372
0
      queue->waiting_threads++;
373
0
      while (!g_queue_peek_tail_link (&queue->queue))
374
0
        {
375
0
    if (end_time == -1)
376
0
      g_cond_wait (&queue->cond, &queue->mutex);
377
0
    else
378
0
      {
379
0
        if (!g_cond_wait_until (&queue->cond, &queue->mutex, end_time))
380
0
    break;
381
0
      }
382
0
        }
383
0
      queue->waiting_threads--;
384
0
    }
385
386
0
  retval = g_queue_pop_tail (&queue->queue);
387
388
0
  g_assert (retval || !wait || end_time > 0);
389
390
0
  return retval;
391
0
}
392
393
/**
394
 * g_async_queue_pop:
395
 * @queue: a #GAsyncQueue
396
 *
397
 * Pops data from the @queue. If @queue is empty, this function
398
 * blocks until data becomes available.
399
 *
400
 * Returns: (not nullable) (transfer full): data from the queue
401
 */
402
gpointer
403
g_async_queue_pop (GAsyncQueue *queue)
404
0
{
405
0
  gpointer retval;
406
407
0
  g_return_val_if_fail (queue, NULL);
408
409
0
  g_mutex_lock (&queue->mutex);
410
0
  retval = g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
411
0
  g_mutex_unlock (&queue->mutex);
412
413
0
  return retval;
414
0
}
415
416
/**
417
 * g_async_queue_pop_unlocked:
418
 * @queue: a #GAsyncQueue
419
 *
420
 * Pops data from the @queue. If @queue is empty, this function
421
 * blocks until data becomes available.
422
 *
423
 * This function must be called while holding the @queue's lock.
424
 *
425
 * Returns: (not nullable) (transfer full): data from the queue.
426
 */
427
gpointer
428
g_async_queue_pop_unlocked (GAsyncQueue *queue)
429
0
{
430
0
  g_return_val_if_fail (queue, NULL);
431
432
0
  return g_async_queue_pop_intern_unlocked (queue, TRUE, -1);
433
0
}
434
435
/**
436
 * g_async_queue_try_pop:
437
 * @queue: a #GAsyncQueue
438
 *
439
 * Tries to pop data from the @queue. If no data is available,
440
 * %NULL is returned.
441
 *
442
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
443
 *   data is available immediately.
444
 */
445
gpointer
446
g_async_queue_try_pop (GAsyncQueue *queue)
447
0
{
448
0
  gpointer retval;
449
450
0
  g_return_val_if_fail (queue, NULL);
451
452
0
  g_mutex_lock (&queue->mutex);
453
0
  retval = g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
454
0
  g_mutex_unlock (&queue->mutex);
455
456
0
  return retval;
457
0
}
458
459
/**
460
 * g_async_queue_try_pop_unlocked:
461
 * @queue: a #GAsyncQueue
462
 *
463
 * Tries to pop data from the @queue. If no data is available,
464
 * %NULL is returned.
465
 *
466
 * This function must be called while holding the @queue's lock.
467
 *
468
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
469
 *   data is available immediately.
470
 */
471
gpointer
472
g_async_queue_try_pop_unlocked (GAsyncQueue *queue)
473
0
{
474
0
  g_return_val_if_fail (queue, NULL);
475
476
0
  return g_async_queue_pop_intern_unlocked (queue, FALSE, -1);
477
0
}
478
479
/**
480
 * g_async_queue_timeout_pop:
481
 * @queue: a #GAsyncQueue
482
 * @timeout: the number of microseconds to wait
483
 *
484
 * Pops data from the @queue. If the queue is empty, blocks for
485
 * @timeout microseconds, or until data becomes available.
486
 *
487
 * If no data is received before the timeout, %NULL is returned.
488
 *
489
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
490
 *   data is received before the timeout.
491
 */
492
gpointer
493
g_async_queue_timeout_pop (GAsyncQueue *queue,
494
         guint64      timeout)
495
0
{
496
0
  gint64 end_time = g_get_monotonic_time () + timeout;
497
0
  gpointer retval;
498
499
0
  g_return_val_if_fail (queue != NULL, NULL);
500
501
0
  g_mutex_lock (&queue->mutex);
502
0
  retval = g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
503
0
  g_mutex_unlock (&queue->mutex);
504
505
0
  return retval;
506
0
}
507
508
/**
509
 * g_async_queue_timeout_pop_unlocked:
510
 * @queue: a #GAsyncQueue
511
 * @timeout: the number of microseconds to wait
512
 *
513
 * Pops data from the @queue. If the queue is empty, blocks for
514
 * @timeout microseconds, or until data becomes available.
515
 *
516
 * If no data is received before the timeout, %NULL is returned.
517
 *
518
 * This function must be called while holding the @queue's lock.
519
 *
520
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
521
 *   data is received before the timeout.
522
 */
523
gpointer
524
g_async_queue_timeout_pop_unlocked (GAsyncQueue *queue,
525
            guint64      timeout)
526
0
{
527
0
  gint64 end_time = g_get_monotonic_time () + timeout;
528
529
0
  g_return_val_if_fail (queue != NULL, NULL);
530
531
0
  return g_async_queue_pop_intern_unlocked (queue, TRUE, end_time);
532
0
}
533
534
/**
535
 * g_async_queue_timed_pop:
536
 * @queue: a #GAsyncQueue
537
 * @end_time: a #GTimeVal, determining the final time
538
 *
539
 * Pops data from the @queue. If the queue is empty, blocks until
540
 * @end_time or until data becomes available.
541
 *
542
 * If no data is received before @end_time, %NULL is returned.
543
 *
544
 * To easily calculate @end_time, a combination of g_get_real_time()
545
 * and g_time_val_add() can be used.
546
 *
547
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
548
 *   data is received before @end_time.
549
 *
550
 * Deprecated: use g_async_queue_timeout_pop().
551
 */
552
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
553
gpointer
554
g_async_queue_timed_pop (GAsyncQueue *queue,
555
                         GTimeVal    *end_time)
556
0
{
557
0
  gint64 m_end_time;
558
0
  gpointer retval;
559
560
0
  g_return_val_if_fail (queue, NULL);
561
562
0
  if (end_time != NULL)
563
0
    {
564
0
      m_end_time = g_get_monotonic_time () +
565
0
        ((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
566
0
    }
567
0
  else
568
0
    m_end_time = -1;
569
570
0
  g_mutex_lock (&queue->mutex);
571
0
  retval = g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
572
0
  g_mutex_unlock (&queue->mutex);
573
574
0
  return retval;
575
0
}
576
G_GNUC_END_IGNORE_DEPRECATIONS
577
578
/**
579
 * g_async_queue_timed_pop_unlocked:
580
 * @queue: a #GAsyncQueue
581
 * @end_time: a #GTimeVal, determining the final time
582
 *
583
 * Pops data from the @queue. If the queue is empty, blocks until
584
 * @end_time or until data becomes available.
585
 *
586
 * If no data is received before @end_time, %NULL is returned.
587
 *
588
 * To easily calculate @end_time, a combination of g_get_real_time()
589
 * and g_time_val_add() can be used.
590
 *
591
 * This function must be called while holding the @queue's lock.
592
 *
593
 * Returns: (nullable) (transfer full): data from the queue or %NULL, when no
594
 *   data is received before @end_time.
595
 *
596
 * Deprecated: use g_async_queue_timeout_pop_unlocked().
597
 */
598
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
599
gpointer
600
g_async_queue_timed_pop_unlocked (GAsyncQueue *queue,
601
                                  GTimeVal    *end_time)
602
0
{
603
0
  gint64 m_end_time;
604
605
0
  g_return_val_if_fail (queue, NULL);
606
607
0
  if (end_time != NULL)
608
0
    {
609
0
      m_end_time = g_get_monotonic_time () +
610
0
        ((gint64) end_time->tv_sec * G_USEC_PER_SEC + end_time->tv_usec - g_get_real_time ());
611
0
    }
612
0
  else
613
0
    m_end_time = -1;
614
615
0
  return g_async_queue_pop_intern_unlocked (queue, TRUE, m_end_time);
616
0
}
617
G_GNUC_END_IGNORE_DEPRECATIONS
618
619
/**
620
 * g_async_queue_length:
621
 * @queue: a #GAsyncQueue.
622
 *
623
 * Returns the length of the queue.
624
 *
625
 * Actually this function returns the number of data items in
626
 * the queue minus the number of waiting threads, so a negative
627
 * value means waiting threads, and a positive value means available
628
 * entries in the @queue. A return value of 0 could mean n entries
629
 * in the queue and n threads waiting. This can happen due to locking
630
 * of the queue or due to scheduling.
631
 *
632
 * Returns: the length of the @queue
633
 */
634
gint
635
g_async_queue_length (GAsyncQueue *queue)
636
0
{
637
0
  gint retval;
638
639
0
  g_return_val_if_fail (queue, 0);
640
641
0
  g_mutex_lock (&queue->mutex);
642
0
  retval = queue->queue.length - queue->waiting_threads;
643
0
  g_mutex_unlock (&queue->mutex);
644
645
0
  return retval;
646
0
}
647
648
/**
649
 * g_async_queue_length_unlocked:
650
 * @queue: a #GAsyncQueue
651
 *
652
 * Returns the length of the queue.
653
 *
654
 * Actually this function returns the number of data items in
655
 * the queue minus the number of waiting threads, so a negative
656
 * value means waiting threads, and a positive value means available
657
 * entries in the @queue. A return value of 0 could mean n entries
658
 * in the queue and n threads waiting. This can happen due to locking
659
 * of the queue or due to scheduling.
660
 *
661
 * This function must be called while holding the @queue's lock.
662
 *
663
 * Returns: the length of the @queue.
664
 */
665
gint
666
g_async_queue_length_unlocked (GAsyncQueue *queue)
667
0
{
668
0
  g_return_val_if_fail (queue, 0);
669
670
0
  return queue->queue.length - queue->waiting_threads;
671
0
}
672
673
/**
674
 * g_async_queue_sort:
675
 * @queue: a #GAsyncQueue
676
 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
677
 * @user_data: user data passed to @func
678
 *
679
 * Sorts @queue using @func.
680
 *
681
 * The sort function @func is passed two elements of the @queue.
682
 * It should return 0 if they are equal, a negative value if the
683
 * first element should be higher in the @queue or a positive value
684
 * if the first element should be lower in the @queue than the second
685
 * element.
686
 *
687
 * This function will lock @queue before it sorts the queue and unlock
688
 * it when it is finished.
689
 *
690
 * If you were sorting a list of priority numbers to make sure the
691
 * lowest priority would be at the top of the queue, you could use:
692
 * |[<!-- language="C" -->
693
 *  gint32 id1;
694
 *  gint32 id2;
695
 *
696
 *  id1 = GPOINTER_TO_INT (element1);
697
 *  id2 = GPOINTER_TO_INT (element2);
698
 *
699
 *  return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
700
 * ]|
701
 *
702
 * Since: 2.10
703
 */
704
void
705
g_async_queue_sort (GAsyncQueue      *queue,
706
                    GCompareDataFunc  func,
707
                    gpointer          user_data)
708
0
{
709
0
  g_return_if_fail (queue != NULL);
710
0
  g_return_if_fail (func != NULL);
711
712
0
  g_mutex_lock (&queue->mutex);
713
0
  g_async_queue_sort_unlocked (queue, func, user_data);
714
0
  g_mutex_unlock (&queue->mutex);
715
0
}
716
717
/**
718
 * g_async_queue_sort_unlocked:
719
 * @queue: a #GAsyncQueue
720
 * @func: (scope call): the #GCompareDataFunc is used to sort @queue
721
 * @user_data: user data passed to @func
722
 *
723
 * Sorts @queue using @func.
724
 *
725
 * The sort function @func is passed two elements of the @queue.
726
 * It should return 0 if they are equal, a negative value if the
727
 * first element should be higher in the @queue or a positive value
728
 * if the first element should be lower in the @queue than the second
729
 * element.
730
 *
731
 * This function must be called while holding the @queue's lock.
732
 *
733
 * Since: 2.10
734
 */
735
void
736
g_async_queue_sort_unlocked (GAsyncQueue      *queue,
737
                             GCompareDataFunc  func,
738
                             gpointer          user_data)
739
0
{
740
0
  SortData sd;
741
742
0
  g_return_if_fail (queue != NULL);
743
0
  g_return_if_fail (func != NULL);
744
745
0
  sd.func = func;
746
0
  sd.user_data = user_data;
747
748
0
  g_queue_sort (&queue->queue,
749
0
                (GCompareDataFunc)g_async_queue_invert_compare,
750
0
                &sd);
751
0
}
752
753
/**
754
 * g_async_queue_remove:
755
 * @queue: a #GAsyncQueue
756
 * @item: (not nullable) (transfer none): the data to remove from the @queue
757
 *
758
 * Remove an item from the queue.
759
 *
760
 * Returns: %TRUE if the item was removed
761
 *
762
 * Since: 2.46
763
 */
764
gboolean
765
g_async_queue_remove (GAsyncQueue *queue,
766
                      gpointer     item)
767
0
{
768
0
  gboolean ret;
769
770
0
  g_return_val_if_fail (queue != NULL, FALSE);
771
0
  g_return_val_if_fail (item != NULL, FALSE);
772
773
0
  g_mutex_lock (&queue->mutex);
774
0
  ret = g_async_queue_remove_unlocked (queue, item);
775
0
  g_mutex_unlock (&queue->mutex);
776
777
0
  return ret;
778
0
}
779
780
/**
781
 * g_async_queue_remove_unlocked:
782
 * @queue: a #GAsyncQueue
783
 * @item: (not nullable) (transfer none): the data to remove from the @queue
784
 *
785
 * Remove an item from the queue.
786
 *
787
 * This function must be called while holding the @queue's lock.
788
 *
789
 * Returns: %TRUE if the item was removed
790
 *
791
 * Since: 2.46
792
 */
793
gboolean
794
g_async_queue_remove_unlocked (GAsyncQueue *queue,
795
                               gpointer     item)
796
0
{
797
0
  g_return_val_if_fail (queue != NULL, FALSE);
798
0
  g_return_val_if_fail (item != NULL, FALSE);
799
800
0
  return g_queue_remove (&queue->queue, item);
801
0
}
802
803
/**
804
 * g_async_queue_push_front:
805
 * @queue: a #GAsyncQueue
806
 * @item: (not nullable) (transfer full): data to push into the @queue
807
 *
808
 * Pushes the @item into the @queue. @item must not be %NULL.
809
 * In contrast to g_async_queue_push(), this function
810
 * pushes the new item ahead of the items already in the queue,
811
 * so that it will be the next one to be popped off the queue.
812
 *
813
 * Since: 2.46
814
 */
815
void
816
g_async_queue_push_front (GAsyncQueue *queue,
817
                          gpointer     item)
818
0
{
819
0
  g_return_if_fail (queue != NULL);
820
0
  g_return_if_fail (item != NULL);
821
822
0
  g_mutex_lock (&queue->mutex);
823
0
  g_async_queue_push_front_unlocked (queue, item);
824
0
  g_mutex_unlock (&queue->mutex);
825
0
}
826
827
/**
828
 * g_async_queue_push_front_unlocked:
829
 * @queue: a #GAsyncQueue
830
 * @item: (not nullable) (transfer full): data to push into the @queue
831
 *
832
 * Pushes the @item into the @queue. @item must not be %NULL.
833
 * In contrast to g_async_queue_push_unlocked(), this function
834
 * pushes the new item ahead of the items already in the queue,
835
 * so that it will be the next one to be popped off the queue.
836
 *
837
 * This function must be called while holding the @queue's lock.
838
 *
839
 * Since: 2.46
840
 */
841
void
842
g_async_queue_push_front_unlocked (GAsyncQueue *queue,
843
                                   gpointer     item)
844
0
{
845
0
  g_return_if_fail (queue != NULL);
846
0
  g_return_if_fail (item != NULL);
847
848
0
  g_queue_push_tail (&queue->queue, item);
849
0
  if (queue->waiting_threads > 0)
850
0
    g_cond_signal (&queue->cond);
851
0
}
852
853
/*
854
 * Private API
855
 */
856
857
GMutex *
858
_g_async_queue_get_mutex (GAsyncQueue *queue)
859
0
{
860
0
  g_return_val_if_fail (queue, NULL);
861
862
0
  return &queue->mutex;
863
0
}