(root)/
glib-2.79.0/
glib/
gasyncqueue.c
       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  }