Coverage Report

Created: 2025-08-26 06:04

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