Anthony Liguori | d63c947 | 2013-03-25 10:23:56 -0500 | [diff] [blame] | 1 | /* |
| 2 | * GLIB Compatibility Functions |
| 3 | * |
| 4 | * Copyright IBM, Corp. 2013 |
| 5 | * |
| 6 | * Authors: |
| 7 | * Anthony Liguori <aliguori@us.ibm.com> |
Michael Tokarev | 86946a2 | 2014-05-08 12:30:46 +0400 | [diff] [blame] | 8 | * Michael Tokarev <mjt@tls.msk.ru> |
| 9 | * Paolo Bonzini <pbonzini@redhat.com> |
Anthony Liguori | d63c947 | 2013-03-25 10:23:56 -0500 | [diff] [blame] | 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 | |
Stefan Hajnoczi | 89b516d | 2014-10-15 14:29:30 +0200 | [diff] [blame] | 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 | |
Stefan Hajnoczi | 89b516d | 2014-10-15 14:29:30 +0200 | [diff] [blame] | 26 | #if !GLIB_CHECK_VERSION(2, 28, 0) |
Cornelia Huck | 14655e9 | 2015-04-02 17:17:45 +0200 | [diff] [blame] | 27 | static inline gint64 qemu_g_get_monotonic_time(void) |
Stefan Hajnoczi | 89b516d | 2014-10-15 14:29:30 +0200 | [diff] [blame] | 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 | } |
Cornelia Huck | 14655e9 | 2015-04-02 17:17:45 +0200 | [diff] [blame] | 38 | /* work around distro backports of this interface */ |
| 39 | #define g_get_monotonic_time() qemu_g_get_monotonic_time() |
Stefan Hajnoczi | 89b516d | 2014-10-15 14:29:30 +0200 | [diff] [blame] | 40 | #endif |
| 41 | |
Sangho Park | 5a00754 | 2014-05-08 12:47:10 +0400 | [diff] [blame] | 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) |
| 48 | gint g_poll_fixed(GPollFD *fds, guint nfds, gint timeout); |
Stefan Hajnoczi | f95c967 | 2014-05-02 18:35:56 +0400 | [diff] [blame] | 49 | #endif |
| 50 | |
Michael Tokarev | 86946a2 | 2014-05-08 12:30:46 +0400 | [diff] [blame] | 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 | |
| 63 | typedef struct CompatGMutex { |
| 64 | GOnce once; |
| 65 | } CompatGMutex; |
| 66 | |
| 67 | typedef struct CompatGCond { |
| 68 | GOnce once; |
| 69 | } CompatGCond; |
| 70 | |
| 71 | static inline gpointer do_g_mutex_new(gpointer unused) |
| 72 | { |
| 73 | return (gpointer) g_mutex_new(); |
| 74 | } |
| 75 | |
| 76 | static inline void g_mutex_init(CompatGMutex *mutex) |
| 77 | { |
| 78 | mutex->once = (GOnce) G_ONCE_INIT; |
| 79 | } |
| 80 | |
| 81 | static inline void g_mutex_clear(CompatGMutex *mutex) |
| 82 | { |
Michael Tokarev | f20f2a1 | 2015-05-07 13:38:02 +0300 | [diff] [blame] | 83 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
Michael Tokarev | 86946a2 | 2014-05-08 12:30:46 +0400 | [diff] [blame] | 84 | if (mutex->once.retval) { |
| 85 | g_mutex_free((GMutex *) mutex->once.retval); |
| 86 | } |
| 87 | mutex->once = (GOnce) G_ONCE_INIT; |
| 88 | } |
| 89 | |
| 90 | static 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 | |
| 97 | static 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 | |
| 105 | static inline void (g_mutex_unlock)(CompatGMutex *mutex) |
| 106 | { |
| 107 | g_mutex_unlock((GMutex *) mutex->once.retval); |
| 108 | } |
| 109 | #undef g_mutex_unlock |
| 110 | |
| 111 | static inline gpointer do_g_cond_new(gpointer unused) |
| 112 | { |
| 113 | return (gpointer) g_cond_new(); |
| 114 | } |
| 115 | |
| 116 | static inline void g_cond_init(CompatGCond *cond) |
| 117 | { |
| 118 | cond->once = (GOnce) G_ONCE_INIT; |
| 119 | } |
| 120 | |
| 121 | static inline void g_cond_clear(CompatGCond *cond) |
| 122 | { |
Michael Tokarev | f20f2a1 | 2015-05-07 13:38:02 +0300 | [diff] [blame] | 123 | g_assert(cond->once.status != G_ONCE_STATUS_PROGRESS); |
Michael Tokarev | 86946a2 | 2014-05-08 12:30:46 +0400 | [diff] [blame] | 124 | if (cond->once.retval) { |
| 125 | g_cond_free((GCond *) cond->once.retval); |
| 126 | } |
| 127 | cond->once = (GOnce) G_ONCE_INIT; |
| 128 | } |
| 129 | |
| 130 | static inline void (g_cond_wait)(CompatGCond *cond, CompatGMutex *mutex) |
| 131 | { |
Michael Tokarev | f20f2a1 | 2015-05-07 13:38:02 +0300 | [diff] [blame] | 132 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
Michael Tokarev | 86946a2 | 2014-05-08 12:30:46 +0400 | [diff] [blame] | 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 | |
| 138 | static 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 | |
| 145 | static 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() */ |
| 154 | static 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 | |
Markus Armbruster | 8681dff | 2015-10-27 15:44:00 +0100 | [diff] [blame] | 168 | #if !GLIB_CHECK_VERSION(2, 32, 0) |
| 169 | /* Beware, function returns gboolean since 2.39.2, see GLib commit 9101915 */ |
| 170 | static 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 | |
Marc-André Lureau | 8a0b542 | 2015-10-02 14:58:17 +0200 | [diff] [blame] | 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 | |
Anthony Liguori | d63c947 | 2013-03-25 10:23:56 -0500 | [diff] [blame] | 237 | #endif |