]>
Commit | Line | Data |
---|---|---|
d63c9477 AL |
1 | /* |
2 | * GLIB Compatibility Functions | |
3 | * | |
4 | * Copyright IBM, Corp. 2013 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <[email protected]> | |
86946a2d MT |
8 | * Michael Tokarev <[email protected]> |
9 | * Paolo Bonzini <[email protected]> | |
d63c9477 AL |
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 | ||
89b516d8 SH |
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 | ||
89b516d8 | 26 | #if !GLIB_CHECK_VERSION(2, 28, 0) |
14655e9a | 27 | static inline gint64 qemu_g_get_monotonic_time(void) |
89b516d8 SH |
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 | } | |
14655e9a CH |
38 | /* work around distro backports of this interface */ |
39 | #define g_get_monotonic_time() qemu_g_get_monotonic_time() | |
89b516d8 SH |
40 | #endif |
41 | ||
1706e9d8 | 42 | #if defined(_WIN32) && !GLIB_CHECK_VERSION(2, 50, 0) |
5a007547 SP |
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); | |
f95c967a SH |
49 | #endif |
50 | ||
50455700 SS |
51 | #if !GLIB_CHECK_VERSION(2, 30, 0) |
52 | /* Not a 100% compatible implementation, but good enough for most | |
53 | * cases. Placeholders are only supported at the end of the | |
54 | * template. */ | |
55 | static inline gchar *qemu_g_dir_make_tmp(gchar const *tmpl, GError **error) | |
56 | { | |
57 | gchar *path = g_build_filename(g_get_tmp_dir(), tmpl ?: ".XXXXXX", NULL); | |
58 | ||
59 | if (mkdtemp(path) != NULL) { | |
60 | return path; | |
61 | } | |
62 | /* Error occurred, clean up. */ | |
63 | g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), | |
64 | "mkdtemp() failed"); | |
65 | g_free(path); | |
66 | return NULL; | |
67 | } | |
68 | #define g_dir_make_tmp(tmpl, error) qemu_g_dir_make_tmp(tmpl, error) | |
69 | #endif /* glib 2.30 */ | |
70 | ||
86946a2d MT |
71 | #if !GLIB_CHECK_VERSION(2, 31, 0) |
72 | /* before glib-2.31, GMutex and GCond was dynamic-only (there was a separate | |
73 | * GStaticMutex, but it didn't work with condition variables). | |
74 | * | |
75 | * Our implementation uses GOnce to fake a static implementation that does | |
76 | * not require separate initialization. | |
77 | * We need to rename the types to avoid passing our CompatGMutex/CompatGCond | |
78 | * by mistake to a function that expects GMutex/GCond. However, for ease | |
79 | * of use we keep the GLib function names. GLib uses macros for the | |
80 | * implementation, we use inline functions instead and undefine the macros. | |
81 | */ | |
82 | ||
83 | typedef struct CompatGMutex { | |
84 | GOnce once; | |
85 | } CompatGMutex; | |
86 | ||
87 | typedef struct CompatGCond { | |
88 | GOnce once; | |
89 | } CompatGCond; | |
90 | ||
91 | static inline gpointer do_g_mutex_new(gpointer unused) | |
92 | { | |
93 | return (gpointer) g_mutex_new(); | |
94 | } | |
95 | ||
96 | static inline void g_mutex_init(CompatGMutex *mutex) | |
97 | { | |
98 | mutex->once = (GOnce) G_ONCE_INIT; | |
99 | } | |
100 | ||
101 | static inline void g_mutex_clear(CompatGMutex *mutex) | |
102 | { | |
f20f2a1f | 103 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
104 | if (mutex->once.retval) { |
105 | g_mutex_free((GMutex *) mutex->once.retval); | |
106 | } | |
107 | mutex->once = (GOnce) G_ONCE_INIT; | |
108 | } | |
109 | ||
110 | static inline void (g_mutex_lock)(CompatGMutex *mutex) | |
111 | { | |
112 | g_once(&mutex->once, do_g_mutex_new, NULL); | |
113 | g_mutex_lock((GMutex *) mutex->once.retval); | |
114 | } | |
115 | #undef g_mutex_lock | |
116 | ||
117 | static inline gboolean (g_mutex_trylock)(CompatGMutex *mutex) | |
118 | { | |
119 | g_once(&mutex->once, do_g_mutex_new, NULL); | |
120 | return g_mutex_trylock((GMutex *) mutex->once.retval); | |
121 | } | |
122 | #undef g_mutex_trylock | |
123 | ||
124 | ||
125 | static inline void (g_mutex_unlock)(CompatGMutex *mutex) | |
126 | { | |
127 | g_mutex_unlock((GMutex *) mutex->once.retval); | |
128 | } | |
129 | #undef g_mutex_unlock | |
130 | ||
131 | static inline gpointer do_g_cond_new(gpointer unused) | |
132 | { | |
133 | return (gpointer) g_cond_new(); | |
134 | } | |
135 | ||
136 | static inline void g_cond_init(CompatGCond *cond) | |
137 | { | |
138 | cond->once = (GOnce) G_ONCE_INIT; | |
139 | } | |
140 | ||
141 | static inline void g_cond_clear(CompatGCond *cond) | |
142 | { | |
f20f2a1f | 143 | g_assert(cond->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
144 | if (cond->once.retval) { |
145 | g_cond_free((GCond *) cond->once.retval); | |
146 | } | |
147 | cond->once = (GOnce) G_ONCE_INIT; | |
148 | } | |
149 | ||
150 | static inline void (g_cond_wait)(CompatGCond *cond, CompatGMutex *mutex) | |
151 | { | |
f20f2a1f | 152 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
153 | g_once(&cond->once, do_g_cond_new, NULL); |
154 | g_cond_wait((GCond *) cond->once.retval, (GMutex *) mutex->once.retval); | |
155 | } | |
156 | #undef g_cond_wait | |
157 | ||
158 | static inline void (g_cond_broadcast)(CompatGCond *cond) | |
159 | { | |
160 | g_once(&cond->once, do_g_cond_new, NULL); | |
161 | g_cond_broadcast((GCond *) cond->once.retval); | |
162 | } | |
163 | #undef g_cond_broadcast | |
164 | ||
165 | static inline void (g_cond_signal)(CompatGCond *cond) | |
166 | { | |
167 | g_once(&cond->once, do_g_cond_new, NULL); | |
168 | g_cond_signal((GCond *) cond->once.retval); | |
169 | } | |
170 | #undef g_cond_signal | |
171 | ||
634d39b4 PB |
172 | static inline gboolean (g_cond_timed_wait)(CompatGCond *cond, |
173 | CompatGMutex *mutex, | |
174 | GTimeVal *time) | |
175 | { | |
176 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); | |
177 | g_once(&cond->once, do_g_cond_new, NULL); | |
178 | return g_cond_timed_wait((GCond *) cond->once.retval, | |
179 | (GMutex *) mutex->once.retval, time); | |
180 | } | |
181 | #undef g_cond_timed_wait | |
182 | ||
183 | /* This is not a macro, because it didn't exist until 2.32. */ | |
184 | static inline gboolean g_cond_wait_until(CompatGCond *cond, CompatGMutex *mutex, | |
185 | gint64 end_time) | |
186 | { | |
187 | GTimeVal time; | |
188 | ||
189 | /* Convert from monotonic to CLOCK_REALTIME. */ | |
190 | end_time -= g_get_monotonic_time(); | |
191 | g_get_current_time(&time); | |
192 | end_time += time.tv_sec * G_TIME_SPAN_SECOND + time.tv_usec; | |
193 | ||
194 | time.tv_sec = end_time / G_TIME_SPAN_SECOND; | |
195 | time.tv_usec = end_time % G_TIME_SPAN_SECOND; | |
196 | return g_cond_timed_wait(cond, mutex, &time); | |
197 | } | |
86946a2d MT |
198 | |
199 | /* before 2.31 there was no g_thread_new() */ | |
200 | static inline GThread *g_thread_new(const char *name, | |
201 | GThreadFunc func, gpointer data) | |
202 | { | |
203 | GThread *thread = g_thread_create(func, data, TRUE, NULL); | |
204 | if (!thread) { | |
205 | g_error("creating thread"); | |
206 | } | |
207 | return thread; | |
208 | } | |
209 | #else | |
210 | #define CompatGMutex GMutex | |
211 | #define CompatGCond GCond | |
212 | #endif /* glib 2.31 */ | |
213 | ||
8681dffa MA |
214 | #if !GLIB_CHECK_VERSION(2, 32, 0) |
215 | /* Beware, function returns gboolean since 2.39.2, see GLib commit 9101915 */ | |
216 | static inline void g_hash_table_add(GHashTable *hash_table, gpointer key) | |
217 | { | |
218 | g_hash_table_replace(hash_table, key, key); | |
219 | } | |
161a56a9 VF |
220 | |
221 | static inline gboolean g_hash_table_contains(GHashTable *hash_table, | |
222 | gpointer key) | |
223 | { | |
224 | return g_hash_table_lookup_extended(hash_table, key, NULL, NULL); | |
225 | } | |
8681dffa MA |
226 | #endif |
227 | ||
8a0b5421 MAL |
228 | #ifndef g_assert_true |
229 | #define g_assert_true(expr) \ | |
230 | do { \ | |
231 | if (G_LIKELY(expr)) { \ | |
232 | } else { \ | |
233 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
234 | "'" #expr "' should be TRUE"); \ | |
235 | } \ | |
236 | } while (0) | |
237 | #endif | |
238 | ||
239 | #ifndef g_assert_false | |
240 | #define g_assert_false(expr) \ | |
241 | do { \ | |
242 | if (G_LIKELY(!(expr))) { \ | |
243 | } else { \ | |
244 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
245 | "'" #expr "' should be FALSE"); \ | |
246 | } \ | |
247 | } while (0) | |
248 | #endif | |
249 | ||
250 | #ifndef g_assert_null | |
251 | #define g_assert_null(expr) \ | |
252 | do { \ | |
253 | if (G_LIKELY((expr) == NULL)) { \ | |
254 | } else { \ | |
255 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
256 | "'" #expr "' should be NULL"); \ | |
257 | } \ | |
258 | } while (0) | |
259 | #endif | |
260 | ||
261 | #ifndef g_assert_nonnull | |
262 | #define g_assert_nonnull(expr) \ | |
263 | do { \ | |
264 | if (G_LIKELY((expr) != NULL)) { \ | |
265 | } else { \ | |
266 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
267 | "'" #expr "' should not be NULL"); \ | |
268 | } \ | |
269 | } while (0) | |
270 | #endif | |
271 | ||
272 | #ifndef g_assert_cmpmem | |
273 | #define g_assert_cmpmem(m1, l1, m2, l2) \ | |
274 | do { \ | |
275 | gconstpointer __m1 = m1, __m2 = m2; \ | |
276 | int __l1 = l1, __l2 = l2; \ | |
277 | if (__l1 != __l2) { \ | |
278 | g_assertion_message_cmpnum( \ | |
279 | G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
280 | #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", \ | |
281 | __l2, 'i'); \ | |
282 | } else if (memcmp(__m1, __m2, __l1) != 0) { \ | |
283 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
284 | "assertion failed (" #m1 " == " #m2 ")"); \ | |
285 | } \ | |
286 | } while (0) | |
287 | #endif | |
288 | ||
5c7e3e9f MAL |
289 | #if !GLIB_CHECK_VERSION(2, 28, 0) |
290 | static inline void g_list_free_full(GList *list, GDestroyNotify free_func) | |
291 | { | |
292 | GList *l; | |
293 | ||
294 | for (l = list; l; l = l->next) { | |
295 | free_func(l->data); | |
296 | } | |
297 | ||
298 | g_list_free(list); | |
299 | } | |
300 | ||
301 | static inline void g_slist_free_full(GSList *list, GDestroyNotify free_func) | |
302 | { | |
303 | GSList *l; | |
304 | ||
305 | for (l = list; l; l = l->next) { | |
306 | free_func(l->data); | |
307 | } | |
308 | ||
309 | g_slist_free(list); | |
310 | } | |
311 | #endif | |
312 | ||
20f4aa26 DB |
313 | #if !GLIB_CHECK_VERSION(2, 26, 0) |
314 | static inline void g_source_set_name(GSource *source, const char *name) | |
315 | { | |
316 | /* This is just a debugging aid, so leaving it a no-op */ | |
317 | } | |
e93a68e1 DB |
318 | static inline void g_source_set_name_by_id(guint tag, const char *name) |
319 | { | |
320 | /* This is just a debugging aid, so leaving it a no-op */ | |
321 | } | |
20f4aa26 DB |
322 | #endif |
323 | ||
28017e01 PB |
324 | #if !GLIB_CHECK_VERSION(2, 36, 0) |
325 | /* Always fail. This will not include error_report output in the test log, | |
326 | * sending it instead to stderr. | |
327 | */ | |
328 | #define g_test_initialized() (0) | |
329 | #endif | |
330 | #if !GLIB_CHECK_VERSION(2, 38, 0) | |
331 | #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS | |
332 | #error schizophrenic detection of glib subprocess testing | |
333 | #endif | |
334 | #define g_test_subprocess() (0) | |
335 | #endif | |
336 | ||
461a8620 MAL |
337 | |
338 | #if !GLIB_CHECK_VERSION(2, 34, 0) | |
339 | static inline void | |
340 | g_test_add_data_func_full(const char *path, | |
341 | gpointer data, | |
342 | gpointer fn, | |
343 | gpointer data_free_func) | |
344 | { | |
345 | #if GLIB_CHECK_VERSION(2, 26, 0) | |
346 | /* back-compat casts, remove this once we can require new-enough glib */ | |
347 | g_test_add_vtable(path, 0, data, NULL, | |
348 | (GTestFixtureFunc)fn, (GTestFixtureFunc) data_free_func); | |
349 | #else | |
350 | /* back-compat casts, remove this once we can require new-enough glib */ | |
351 | g_test_add_vtable(path, 0, data, NULL, | |
352 | (void (*)(void)) fn, (void (*)(void)) data_free_func); | |
353 | #endif | |
354 | } | |
355 | #endif | |
356 | ||
357 | ||
d63c9477 | 358 | #endif |