Coverage Report

Created: 2025-08-26 06:55

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