qemu/include/glib-compat.h
<<
>>
Prefs
   1/*
   2 * GLIB Compatibility Functions
   3 *
   4 * Copyright IBM, Corp. 2013
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.ibm.com>
   8 *  Michael Tokarev   <mjt@tls.msk.ru>
   9 *  Paolo Bonzini     <pbonzini@redhat.com>
  10 *
  11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12 * See the COPYING file in the top-level directory.
  13 *
  14 */
  15
  16#ifndef QEMU_GLIB_COMPAT_H
  17#define QEMU_GLIB_COMPAT_H
  18
  19#include <glib.h>
  20
  21/* GLIB version compatibility flags */
  22#if !GLIB_CHECK_VERSION(2, 26, 0)
  23#define G_TIME_SPAN_SECOND              (G_GINT64_CONSTANT(1000000))
  24#endif
  25
  26#if !GLIB_CHECK_VERSION(2, 28, 0)
  27static inline gint64 qemu_g_get_monotonic_time(void)
  28{
  29    /* g_get_monotonic_time() is best-effort so we can use the wall clock as a
  30     * fallback.
  31     */
  32
  33    GTimeVal time;
  34    g_get_current_time(&time);
  35
  36    return time.tv_sec * G_TIME_SPAN_SECOND + time.tv_usec;
  37}
  38/* work around distro backports of this interface */
  39#define g_get_monotonic_time() qemu_g_get_monotonic_time()
  40#endif
  41
  42#ifdef _WIN32
  43/*
  44 * g_poll has a problem on Windows when using
  45 * timeouts < 10ms, so use wrapper.
  46 */
  47#define g_poll(fds, nfds, timeout) g_poll_fixed(fds, nfds, timeout)
  48gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout);
  49#endif
  50
  51#if !GLIB_CHECK_VERSION(2, 31, 0)
  52/* before glib-2.31, GMutex and GCond was dynamic-only (there was a separate
  53 * GStaticMutex, but it didn't work with condition variables).
  54 *
  55 * Our implementation uses GOnce to fake a static implementation that does
  56 * not require separate initialization.
  57 * We need to rename the types to avoid passing our CompatGMutex/CompatGCond
  58 * by mistake to a function that expects GMutex/GCond.  However, for ease
  59 * of use we keep the GLib function names.  GLib uses macros for the
  60 * implementation, we use inline functions instead and undefine the macros.
  61 */
  62
  63typedef struct CompatGMutex {
  64    GOnce once;
  65} CompatGMutex;
  66
  67typedef struct CompatGCond {
  68    GOnce once;
  69} CompatGCond;
  70
  71static inline gpointer do_g_mutex_new(gpointer unused)
  72{
  73    return (gpointer) g_mutex_new();
  74}
  75
  76static inline void g_mutex_init(CompatGMutex *mutex)
  77{
  78    mutex->once = (GOnce) G_ONCE_INIT;
  79}
  80
  81static inline void g_mutex_clear(CompatGMutex *mutex)
  82{
  83    g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
  84    if (mutex->once.retval) {
  85        g_mutex_free((GMutex *) mutex->once.retval);
  86    }
  87    mutex->once = (GOnce) G_ONCE_INIT;
  88}
  89
  90static inline void (g_mutex_lock)(CompatGMutex *mutex)
  91{
  92    g_once(&mutex->once, do_g_mutex_new, NULL);
  93    g_mutex_lock((GMutex *) mutex->once.retval);
  94}
  95#undef g_mutex_lock
  96
  97static inline gboolean (g_mutex_trylock)(CompatGMutex *mutex)
  98{
  99    g_once(&mutex->once, do_g_mutex_new, NULL);
 100    return g_mutex_trylock((GMutex *) mutex->once.retval);
 101}
 102#undef g_mutex_trylock
 103
 104
 105static inline void (g_mutex_unlock)(CompatGMutex *mutex)
 106{
 107    g_mutex_unlock((GMutex *) mutex->once.retval);
 108}
 109#undef g_mutex_unlock
 110
 111static inline gpointer do_g_cond_new(gpointer unused)
 112{
 113    return (gpointer) g_cond_new();
 114}
 115
 116static inline void g_cond_init(CompatGCond *cond)
 117{
 118    cond->once = (GOnce) G_ONCE_INIT;
 119}
 120
 121static inline void g_cond_clear(CompatGCond *cond)
 122{
 123    g_assert(cond->once.status != G_ONCE_STATUS_PROGRESS);
 124    if (cond->once.retval) {
 125        g_cond_free((GCond *) cond->once.retval);
 126    }
 127    cond->once = (GOnce) G_ONCE_INIT;
 128}
 129
 130static inline void (g_cond_wait)(CompatGCond *cond, CompatGMutex *mutex)
 131{
 132    g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
 133    g_once(&cond->once, do_g_cond_new, NULL);
 134    g_cond_wait((GCond *) cond->once.retval, (GMutex *) mutex->once.retval);
 135}
 136#undef g_cond_wait
 137
 138static inline void (g_cond_broadcast)(CompatGCond *cond)
 139{
 140    g_once(&cond->once, do_g_cond_new, NULL);
 141    g_cond_broadcast((GCond *) cond->once.retval);
 142}
 143#undef g_cond_broadcast
 144
 145static inline void (g_cond_signal)(CompatGCond *cond)
 146{
 147    g_once(&cond->once, do_g_cond_new, NULL);
 148    g_cond_signal((GCond *) cond->once.retval);
 149}
 150#undef g_cond_signal
 151
 152
 153/* before 2.31 there was no g_thread_new() */
 154static inline GThread *g_thread_new(const char *name,
 155                                    GThreadFunc func, gpointer data)
 156{
 157    GThread *thread = g_thread_create(func, data, TRUE, NULL);
 158    if (!thread) {
 159        g_error("creating thread");
 160    }
 161    return thread;
 162}
 163#else
 164#define CompatGMutex GMutex
 165#define CompatGCond GCond
 166#endif /* glib 2.31 */
 167
 168#if !GLIB_CHECK_VERSION(2, 32, 0)
 169/* Beware, function returns gboolean since 2.39.2, see GLib commit 9101915 */
 170static inline void g_hash_table_add(GHashTable *hash_table, gpointer key)
 171{
 172    g_hash_table_replace(hash_table, key, key);
 173}
 174#endif
 175
 176#ifndef g_assert_true
 177#define g_assert_true(expr)                                                    \
 178    do {                                                                       \
 179        if (G_LIKELY(expr)) {                                                  \
 180        } else {                                                               \
 181            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
 182                                "'" #expr "' should be TRUE");                 \
 183        }                                                                      \
 184    } while (0)
 185#endif
 186
 187#ifndef g_assert_false
 188#define g_assert_false(expr)                                                   \
 189    do {                                                                       \
 190        if (G_LIKELY(!(expr))) {                                               \
 191        } else {                                                               \
 192            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
 193                                "'" #expr "' should be FALSE");                \
 194        }                                                                      \
 195    } while (0)
 196#endif
 197
 198#ifndef g_assert_null
 199#define g_assert_null(expr)                                                    \
 200    do {                                                                       \
 201        if (G_LIKELY((expr) == NULL)) {                                        \
 202        } else {                                                               \
 203            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
 204                                "'" #expr "' should be NULL");                 \
 205        }                                                                      \
 206    } while (0)
 207#endif
 208
 209#ifndef g_assert_nonnull
 210#define g_assert_nonnull(expr)                                                 \
 211    do {                                                                       \
 212        if (G_LIKELY((expr) != NULL)) {                                        \
 213        } else {                                                               \
 214            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
 215                                "'" #expr "' should not be NULL");             \
 216        }                                                                      \
 217    } while (0)
 218#endif
 219
 220#ifndef g_assert_cmpmem
 221#define g_assert_cmpmem(m1, l1, m2, l2)                                        \
 222    do {                                                                       \
 223        gconstpointer __m1 = m1, __m2 = m2;                                    \
 224        int __l1 = l1, __l2 = l2;                                              \
 225        if (__l1 != __l2) {                                                    \
 226            g_assertion_message_cmpnum(                                        \
 227                G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,                   \
 228                #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==",   \
 229                __l2, 'i');                                                    \
 230        } else if (memcmp(__m1, __m2, __l1) != 0) {                            \
 231            g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC,   \
 232                                "assertion failed (" #m1 " == " #m2 ")");      \
 233        }                                                                      \
 234    } while (0)
 235#endif
 236
 237#endif
 238