(root)/
glib-2.79.0/
glib/
gthread.h
       1  /* GLIB - Library of useful routines for C programming
       2   * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful, but
      12   * WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  /*
      21   * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22   * file for a list of people on the GLib Team.  See the ChangeLog
      23   * files for a list of changes.  These files are distributed with
      24   * GLib at ftp://ftp.gtk.org/pub/gtk/.
      25   */
      26  
      27  #ifndef __G_THREAD_H__
      28  #define __G_THREAD_H__
      29  
      30  #if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
      31  #error "Only <glib.h> can be included directly."
      32  #endif
      33  
      34  #include <glib/gatomic.h>
      35  #include <glib/gerror.h>
      36  #include <glib/gutils.h>
      37  
      38  G_BEGIN_DECLS
      39  
      40  #define G_THREAD_ERROR g_thread_error_quark ()
      41  GLIB_AVAILABLE_IN_ALL
      42  GQuark g_thread_error_quark (void);
      43  
      44  typedef enum
      45  {
      46    G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */
      47  } GThreadError;
      48  
      49  typedef gpointer (*GThreadFunc) (gpointer data);
      50  
      51  typedef struct _GThread         GThread;
      52  
      53  typedef union  _GMutex          GMutex;
      54  typedef struct _GRecMutex       GRecMutex;
      55  typedef struct _GRWLock         GRWLock;
      56  typedef struct _GCond           GCond;
      57  typedef struct _GPrivate        GPrivate;
      58  typedef struct _GOnce           GOnce;
      59  
      60  union _GMutex
      61  {
      62    /*< private >*/
      63    gpointer p;
      64    guint i[2];
      65  };
      66  
      67  struct _GRWLock
      68  {
      69    /*< private >*/
      70    gpointer p;
      71    guint i[2];
      72  };
      73  
      74  struct _GCond
      75  {
      76    /*< private >*/
      77    gpointer p;
      78    guint i[2];
      79  };
      80  
      81  struct _GRecMutex
      82  {
      83    /*< private >*/
      84    gpointer p;
      85    guint i[2];
      86  };
      87  
      88  #define G_PRIVATE_INIT(notify) { NULL, (notify), { NULL, NULL } }
      89  struct _GPrivate
      90  {
      91    /*< private >*/
      92    gpointer       p;
      93    GDestroyNotify notify;
      94    gpointer future[2];
      95  };
      96  
      97  typedef enum
      98  {
      99    G_ONCE_STATUS_NOTCALLED,
     100    G_ONCE_STATUS_PROGRESS,
     101    G_ONCE_STATUS_READY
     102  } GOnceStatus;
     103  
     104  #define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL }
     105  struct _GOnce
     106  {
     107    volatile GOnceStatus status;
     108    volatile gpointer retval;
     109  };
     110  
     111  #define G_LOCK_NAME(name)             g__ ## name ## _lock
     112  #define G_LOCK_DEFINE_STATIC(name)    static G_LOCK_DEFINE (name)
     113  #define G_LOCK_DEFINE(name)           GMutex G_LOCK_NAME (name)
     114  #define G_LOCK_EXTERN(name)           extern GMutex G_LOCK_NAME (name)
     115  
     116  #ifdef G_DEBUG_LOCKS
     117  #  define G_LOCK(name)                G_STMT_START{             \
     118        g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \
     119               "file %s: line %d (%s): locking: %s ",             \
     120               __FILE__,        __LINE__, G_STRFUNC,              \
     121               #name);                                            \
     122        g_mutex_lock (&G_LOCK_NAME (name));                       \
     123     }G_STMT_END
     124  #  define G_UNLOCK(name)              G_STMT_START{             \
     125        g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                   \
     126               "file %s: line %d (%s): unlocking: %s ",           \
     127               __FILE__,        __LINE__, G_STRFUNC,              \
     128               #name);                                            \
     129       g_mutex_unlock (&G_LOCK_NAME (name));                      \
     130     }G_STMT_END
     131  #  define G_TRYLOCK(name)                                       \
     132        (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,                  \
     133               "file %s: line %d (%s): try locking: %s ",         \
     134               __FILE__,        __LINE__, G_STRFUNC,              \
     135               #name), g_mutex_trylock (&G_LOCK_NAME (name)))
     136  #else  /* !G_DEBUG_LOCKS */
     137  #  define G_LOCK(name) g_mutex_lock       (&G_LOCK_NAME (name))
     138  #  define G_UNLOCK(name) g_mutex_unlock   (&G_LOCK_NAME (name))
     139  #  define G_TRYLOCK(name) g_mutex_trylock (&G_LOCK_NAME (name))
     140  #endif /* !G_DEBUG_LOCKS */
     141  
     142  GLIB_AVAILABLE_IN_2_32
     143  GThread *       g_thread_ref                    (GThread        *thread);
     144  GLIB_AVAILABLE_IN_2_32
     145  void            g_thread_unref                  (GThread        *thread);
     146  GLIB_AVAILABLE_IN_2_32
     147  GThread *       g_thread_new                    (const gchar    *name,
     148                                                   GThreadFunc     func,
     149                                                   gpointer        data);
     150  GLIB_AVAILABLE_IN_2_32
     151  GThread *       g_thread_try_new                (const gchar    *name,
     152                                                   GThreadFunc     func,
     153                                                   gpointer        data,
     154                                                   GError        **error);
     155  GLIB_AVAILABLE_IN_ALL
     156  GThread *       g_thread_self                   (void);
     157  G_NORETURN GLIB_AVAILABLE_IN_ALL
     158  void            g_thread_exit                   (gpointer        retval);
     159  GLIB_AVAILABLE_IN_ALL
     160  gpointer        g_thread_join                   (GThread        *thread);
     161  GLIB_AVAILABLE_IN_ALL
     162  void            g_thread_yield                  (void);
     163  
     164  
     165  GLIB_AVAILABLE_IN_2_32
     166  void            g_mutex_init                    (GMutex         *mutex);
     167  GLIB_AVAILABLE_IN_2_32
     168  void            g_mutex_clear                   (GMutex         *mutex);
     169  GLIB_AVAILABLE_IN_ALL
     170  void            g_mutex_lock                    (GMutex         *mutex);
     171  GLIB_AVAILABLE_IN_ALL
     172  gboolean        g_mutex_trylock                 (GMutex         *mutex);
     173  GLIB_AVAILABLE_IN_ALL
     174  void            g_mutex_unlock                  (GMutex         *mutex);
     175  
     176  GLIB_AVAILABLE_IN_2_32
     177  void            g_rw_lock_init                  (GRWLock        *rw_lock);
     178  GLIB_AVAILABLE_IN_2_32
     179  void            g_rw_lock_clear                 (GRWLock        *rw_lock);
     180  GLIB_AVAILABLE_IN_2_32
     181  void            g_rw_lock_writer_lock           (GRWLock        *rw_lock);
     182  GLIB_AVAILABLE_IN_2_32
     183  gboolean        g_rw_lock_writer_trylock        (GRWLock        *rw_lock);
     184  GLIB_AVAILABLE_IN_2_32
     185  void            g_rw_lock_writer_unlock         (GRWLock        *rw_lock);
     186  GLIB_AVAILABLE_IN_2_32
     187  void            g_rw_lock_reader_lock           (GRWLock        *rw_lock);
     188  GLIB_AVAILABLE_IN_2_32
     189  gboolean        g_rw_lock_reader_trylock        (GRWLock        *rw_lock);
     190  GLIB_AVAILABLE_IN_2_32
     191  void            g_rw_lock_reader_unlock         (GRWLock        *rw_lock);
     192  
     193  GLIB_AVAILABLE_IN_2_32
     194  void            g_rec_mutex_init                (GRecMutex      *rec_mutex);
     195  GLIB_AVAILABLE_IN_2_32
     196  void            g_rec_mutex_clear               (GRecMutex      *rec_mutex);
     197  GLIB_AVAILABLE_IN_2_32
     198  void            g_rec_mutex_lock                (GRecMutex      *rec_mutex);
     199  GLIB_AVAILABLE_IN_2_32
     200  gboolean        g_rec_mutex_trylock             (GRecMutex      *rec_mutex);
     201  GLIB_AVAILABLE_IN_2_32
     202  void            g_rec_mutex_unlock              (GRecMutex      *rec_mutex);
     203  
     204  GLIB_AVAILABLE_IN_2_32
     205  void            g_cond_init                     (GCond          *cond);
     206  GLIB_AVAILABLE_IN_2_32
     207  void            g_cond_clear                    (GCond          *cond);
     208  GLIB_AVAILABLE_IN_ALL
     209  void            g_cond_wait                     (GCond          *cond,
     210                                                   GMutex         *mutex);
     211  GLIB_AVAILABLE_IN_ALL
     212  void            g_cond_signal                   (GCond          *cond);
     213  GLIB_AVAILABLE_IN_ALL
     214  void            g_cond_broadcast                (GCond          *cond);
     215  GLIB_AVAILABLE_IN_2_32
     216  gboolean        g_cond_wait_until               (GCond          *cond,
     217                                                   GMutex         *mutex,
     218                                                   gint64          end_time);
     219  
     220  GLIB_AVAILABLE_IN_ALL
     221  gpointer        g_private_get                   (GPrivate       *key);
     222  GLIB_AVAILABLE_IN_ALL
     223  void            g_private_set                   (GPrivate       *key,
     224                                                   gpointer        value);
     225  GLIB_AVAILABLE_IN_2_32
     226  void            g_private_replace               (GPrivate       *key,
     227                                                   gpointer        value);
     228  
     229  GLIB_AVAILABLE_IN_ALL
     230  gpointer        g_once_impl                     (GOnce          *once,
     231                                                   GThreadFunc     func,
     232                                                   gpointer        arg);
     233  GLIB_AVAILABLE_IN_ALL
     234  gboolean        g_once_init_enter               (volatile void  *location);
     235  GLIB_AVAILABLE_IN_ALL
     236  void            g_once_init_leave               (volatile void  *location,
     237                                                   gsize           result);
     238  
     239  GLIB_AVAILABLE_IN_2_80
     240  gboolean g_once_init_enter_pointer              (void *location);
     241  GLIB_AVAILABLE_IN_2_80
     242  void g_once_init_leave_pointer                  (void *location,
     243                                                   gpointer result);
     244  
     245  /* Use C11-style atomic extensions to check the fast path for status=ready. If
     246   * they are not available, fall back to using a mutex and condition variable in
     247   * g_once_impl().
     248   *
     249   * On the C11-style codepath, only the load of once->status needs to be atomic,
     250   * as the writes to it and once->retval in g_once_impl() are related by a
     251   * happens-before relation. Release-acquire semantics are defined such that any
     252   * atomic/non-atomic write which happens-before a store/release is guaranteed to
     253   * be seen by the load/acquire of the same atomic variable. */
     254  #if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) && defined(__ATOMIC_SEQ_CST)
     255  # define g_once(once, func, arg) \
     256    ((__atomic_load_n (&(once)->status, __ATOMIC_ACQUIRE) == G_ONCE_STATUS_READY) ? \
     257     (once)->retval : \
     258     g_once_impl ((once), (func), (arg)))
     259  #else
     260  # define g_once(once, func, arg) g_once_impl ((once), (func), (arg))
     261  #endif
     262  
     263  #ifdef __GNUC__
     264  # define g_once_init_enter(location) \
     265    (G_GNUC_EXTENSION ({                                               \
     266      G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer));       \
     267      (void) (0 ? (gpointer) *(location) : NULL);                      \
     268      (!g_atomic_pointer_get (location) &&                             \
     269       g_once_init_enter (location));                                  \
     270    }))
     271  # define g_once_init_leave(location, result) \
     272    (G_GNUC_EXTENSION ({                                               \
     273      G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer));       \
     274      0 ? (void) (*(location) = (result)) : (void) 0;                  \
     275      g_once_init_leave ((location), (gsize) (result));                \
     276    }))
     277  # define g_once_init_enter_pointer(location)                   \
     278    (G_GNUC_EXTENSION ({                                         \
     279      G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \
     280      (void) (0 ? (gpointer) * (location) : NULL);               \
     281      (!g_atomic_pointer_get (location) &&                       \
     282       g_once_init_enter_pointer (location));                    \
     283    })) GLIB_AVAILABLE_MACRO_IN_2_80
     284  # define g_once_init_leave_pointer(location, result)                        \
     285    (G_GNUC_EXTENSION ({                                                      \
     286      G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer));              \
     287      0 ? (void) (*(location) = (result)) : (void) 0;                         \
     288      g_once_init_leave_pointer ((location), (gpointer) (guintptr) (result)); \
     289    })) GLIB_AVAILABLE_MACRO_IN_2_80
     290  #else
     291  # define g_once_init_enter(location) \
     292    (g_once_init_enter((location)))
     293  # define g_once_init_leave(location, result) \
     294    (g_once_init_leave((location), (gsize) (result)))
     295  # define g_once_init_enter_pointer(location) \
     296    (g_once_init_enter_pointer((location))) \
     297    GLIB_AVAILABLE_MACRO_IN_2_80
     298  # define g_once_init_leave_pointer(location, result) \
     299    (g_once_init_leave_pointer((location), (gpointer) (guintptr) (result))) \
     300    GLIB_AVAILABLE_MACRO_IN_2_80
     301  #endif
     302  
     303  GLIB_AVAILABLE_IN_2_36
     304  guint          g_get_num_processors (void);
     305  
     306  /**
     307   * GMutexLocker:
     308   *
     309   * Opaque type. See g_mutex_locker_new() for details.
     310   * Since: 2.44
     311   */
     312  typedef void GMutexLocker;
     313  
     314  /**
     315   * g_mutex_locker_new:
     316   * @mutex: a mutex to lock
     317   *
     318   * Lock @mutex and return a new #GMutexLocker. Unlock with
     319   * g_mutex_locker_free(). Using g_mutex_unlock() on @mutex
     320   * while a #GMutexLocker exists can lead to undefined behaviour.
     321   *
     322   * No allocation is performed, it is equivalent to a g_mutex_lock() call.
     323   *
     324   * This is intended to be used with g_autoptr().  Note that g_autoptr()
     325   * is only available when using GCC or clang, so the following example
     326   * will only work with those compilers:
     327   * |[
     328   * typedef struct
     329   * {
     330   *   ...
     331   *   GMutex mutex;
     332   *   ...
     333   * } MyObject;
     334   *
     335   * static void
     336   * my_object_do_stuff (MyObject *self)
     337   * {
     338   *   g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&self->mutex);
     339   *
     340   *   // Code with mutex locked here
     341   *
     342   *   if (cond)
     343   *     // No need to unlock
     344   *     return;
     345   *
     346   *   // Optionally early unlock
     347   *   g_clear_pointer (&locker, g_mutex_locker_free);
     348   *
     349   *   // Code with mutex unlocked here
     350   * }
     351   * ]|
     352   *
     353   * Returns: a #GMutexLocker
     354   * Since: 2.44
     355   */
     356  GLIB_AVAILABLE_STATIC_INLINE_IN_2_44
     357  static inline GMutexLocker *
     358  g_mutex_locker_new (GMutex *mutex)
     359  {
     360    g_mutex_lock (mutex);
     361    return (GMutexLocker *) mutex;
     362  }
     363  
     364  /**
     365   * g_mutex_locker_free:
     366   * @locker: a GMutexLocker
     367   *
     368   * Unlock @locker's mutex. See g_mutex_locker_new() for details.
     369   *
     370   * No memory is freed, it is equivalent to a g_mutex_unlock() call.
     371   *
     372   * Since: 2.44
     373   */
     374  GLIB_AVAILABLE_STATIC_INLINE_IN_2_44
     375  static inline void
     376  g_mutex_locker_free (GMutexLocker *locker)
     377  {
     378    g_mutex_unlock ((GMutex *) locker);
     379  }
     380  
     381  /**
     382   * GRecMutexLocker:
     383   *
     384   * Opaque type. See g_rec_mutex_locker_new() for details.
     385   * Since: 2.60
     386   */
     387  typedef void GRecMutexLocker;
     388  
     389  /**
     390   * g_rec_mutex_locker_new:
     391   * @rec_mutex: a recursive mutex to lock
     392   *
     393   * Lock @rec_mutex and return a new #GRecMutexLocker. Unlock with
     394   * g_rec_mutex_locker_free(). Using g_rec_mutex_unlock() on @rec_mutex
     395   * while a #GRecMutexLocker exists can lead to undefined behaviour.
     396   *
     397   * No allocation is performed, it is equivalent to a g_rec_mutex_lock() call.
     398   *
     399   * This is intended to be used with g_autoptr().  Note that g_autoptr()
     400   * is only available when using GCC or clang, so the following example
     401   * will only work with those compilers:
     402   * |[
     403   * typedef struct
     404   * {
     405   *   ...
     406   *   GRecMutex rec_mutex;
     407   *   ...
     408   * } MyObject;
     409   *
     410   * static void
     411   * my_object_do_stuff (MyObject *self)
     412   * {
     413   *   g_autoptr(GRecMutexLocker) locker = g_rec_mutex_locker_new (&self->rec_mutex);
     414   *
     415   *   // Code with rec_mutex locked here
     416   *
     417   *   if (cond)
     418   *     // No need to unlock
     419   *     return;
     420   *
     421   *   // Optionally early unlock
     422   *   g_clear_pointer (&locker, g_rec_mutex_locker_free);
     423   *
     424   *   // Code with rec_mutex unlocked here
     425   * }
     426   * ]|
     427   *
     428   * Returns: a #GRecMutexLocker
     429   * Since: 2.60
     430   */
     431  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     432  GLIB_AVAILABLE_STATIC_INLINE_IN_2_60
     433  static inline GRecMutexLocker *
     434  g_rec_mutex_locker_new (GRecMutex *rec_mutex)
     435  {
     436    g_rec_mutex_lock (rec_mutex);
     437    return (GRecMutexLocker *) rec_mutex;
     438  }
     439  G_GNUC_END_IGNORE_DEPRECATIONS
     440  
     441  /**
     442   * g_rec_mutex_locker_free:
     443   * @locker: a GRecMutexLocker
     444   *
     445   * Unlock @locker's recursive mutex. See g_rec_mutex_locker_new() for details.
     446   *
     447   * No memory is freed, it is equivalent to a g_rec_mutex_unlock() call.
     448   *
     449   * Since: 2.60
     450   */
     451  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     452  GLIB_AVAILABLE_STATIC_INLINE_IN_2_60
     453  static inline void
     454  g_rec_mutex_locker_free (GRecMutexLocker *locker)
     455  {
     456    g_rec_mutex_unlock ((GRecMutex *) locker);
     457  }
     458  G_GNUC_END_IGNORE_DEPRECATIONS
     459  
     460  /**
     461   * GRWLockWriterLocker:
     462   *
     463   * Opaque type. See g_rw_lock_writer_locker_new() for details.
     464   * Since: 2.62
     465   */
     466  typedef void GRWLockWriterLocker;
     467  
     468  /**
     469   * g_rw_lock_writer_locker_new:
     470   * @rw_lock: a #GRWLock
     471   *
     472   * Obtain a write lock on @rw_lock and return a new #GRWLockWriterLocker.
     473   * Unlock with g_rw_lock_writer_locker_free(). Using g_rw_lock_writer_unlock()
     474   * on @rw_lock while a #GRWLockWriterLocker exists can lead to undefined
     475   * behaviour.
     476   *
     477   * No allocation is performed, it is equivalent to a g_rw_lock_writer_lock() call.
     478   *
     479   * This is intended to be used with g_autoptr().  Note that g_autoptr()
     480   * is only available when using GCC or clang, so the following example
     481   * will only work with those compilers:
     482   * |[
     483   * typedef struct
     484   * {
     485   *   ...
     486   *   GRWLock rw_lock;
     487   *   GPtrArray *array;
     488   *   ...
     489   * } MyObject;
     490   *
     491   * static gchar *
     492   * my_object_get_data (MyObject *self, guint index)
     493   * {
     494   *   g_autoptr(GRWLockReaderLocker) locker = g_rw_lock_reader_locker_new (&self->rw_lock);
     495   *
     496   *   // Code with a read lock obtained on rw_lock here
     497   *
     498   *   if (self->array == NULL)
     499   *     // No need to unlock
     500   *     return NULL;
     501   *
     502   *   if (index < self->array->len)
     503   *     // No need to unlock
     504   *     return g_ptr_array_index (self->array, index);
     505   *
     506   *   // Optionally early unlock
     507   *   g_clear_pointer (&locker, g_rw_lock_reader_locker_free);
     508   *
     509   *   // Code with rw_lock unlocked here
     510   *   return NULL;
     511   * }
     512   *
     513   * static void
     514   * my_object_set_data (MyObject *self, guint index, gpointer data)
     515   * {
     516   *   g_autoptr(GRWLockWriterLocker) locker = g_rw_lock_writer_locker_new (&self->rw_lock);
     517   *
     518   *   // Code with a write lock obtained on rw_lock here
     519   *
     520   *   if (self->array == NULL)
     521   *     self->array = g_ptr_array_new ();
     522   *
     523   *   if (cond)
     524   *     // No need to unlock
     525   *     return;
     526   *
     527   *   if (index >= self->array->len)
     528   *     g_ptr_array_set_size (self->array, index+1);
     529   *   g_ptr_array_index (self->array, index) = data;
     530   *
     531   *   // Optionally early unlock
     532   *   g_clear_pointer (&locker, g_rw_lock_writer_locker_free);
     533   *
     534   *   // Code with rw_lock unlocked here
     535   * }
     536   * ]|
     537   *
     538   * Returns: a #GRWLockWriterLocker
     539   * Since: 2.62
     540   */
     541  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     542  GLIB_AVAILABLE_STATIC_INLINE_IN_2_62
     543  static inline GRWLockWriterLocker *
     544  g_rw_lock_writer_locker_new (GRWLock *rw_lock)
     545  {
     546    g_rw_lock_writer_lock (rw_lock);
     547    return (GRWLockWriterLocker *) rw_lock;
     548  }
     549  G_GNUC_END_IGNORE_DEPRECATIONS
     550  
     551  /**
     552   * g_rw_lock_writer_locker_free:
     553   * @locker: a GRWLockWriterLocker
     554   *
     555   * Release a write lock on @locker's read-write lock. See
     556   * g_rw_lock_writer_locker_new() for details.
     557   *
     558   * No memory is freed, it is equivalent to a g_rw_lock_writer_unlock() call.
     559   *
     560   * Since: 2.62
     561   */
     562  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     563  GLIB_AVAILABLE_STATIC_INLINE_IN_2_62
     564  static inline void
     565  g_rw_lock_writer_locker_free (GRWLockWriterLocker *locker)
     566  {
     567    g_rw_lock_writer_unlock ((GRWLock *) locker);
     568  }
     569  G_GNUC_END_IGNORE_DEPRECATIONS
     570  
     571  /**
     572   * GRWLockReaderLocker:
     573   *
     574   * Opaque type. See g_rw_lock_reader_locker_new() for details.
     575   * Since: 2.62
     576   */
     577  typedef void GRWLockReaderLocker;
     578  
     579  /**
     580   * g_rw_lock_reader_locker_new:
     581   * @rw_lock: a #GRWLock
     582   *
     583   * Obtain a read lock on @rw_lock and return a new #GRWLockReaderLocker.
     584   * Unlock with g_rw_lock_reader_locker_free(). Using g_rw_lock_reader_unlock()
     585   * on @rw_lock while a #GRWLockReaderLocker exists can lead to undefined
     586   * behaviour.
     587   *
     588   * No allocation is performed, it is equivalent to a g_rw_lock_reader_lock() call.
     589   *
     590   * This is intended to be used with g_autoptr(). For a code sample, see
     591   * g_rw_lock_writer_locker_new().
     592   *
     593   * Returns: a #GRWLockReaderLocker
     594   * Since: 2.62
     595   */
     596  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     597  GLIB_AVAILABLE_STATIC_INLINE_IN_2_62
     598  static inline GRWLockReaderLocker *
     599  g_rw_lock_reader_locker_new (GRWLock *rw_lock)
     600  {
     601    g_rw_lock_reader_lock (rw_lock);
     602    return (GRWLockReaderLocker *) rw_lock;
     603  }
     604  G_GNUC_END_IGNORE_DEPRECATIONS
     605  
     606  /**
     607   * g_rw_lock_reader_locker_free:
     608   * @locker: a GRWLockReaderLocker
     609   *
     610   * Release a read lock on @locker's read-write lock. See
     611   * g_rw_lock_reader_locker_new() for details.
     612   *
     613   * No memory is freed, it is equivalent to a g_rw_lock_reader_unlock() call.
     614   *
     615   * Since: 2.62
     616   */
     617  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
     618  GLIB_AVAILABLE_STATIC_INLINE_IN_2_62
     619  static inline void
     620  g_rw_lock_reader_locker_free (GRWLockReaderLocker *locker)
     621  {
     622    g_rw_lock_reader_unlock ((GRWLock *) locker);
     623  }
     624  G_GNUC_END_IGNORE_DEPRECATIONS
     625  
     626  G_END_DECLS
     627  
     628  #endif /* __G_THREAD_H__ */