]>
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 | ||
5a007547 SP |
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); | |
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 | } | |
220 | #endif | |
221 | ||
8a0b5421 MAL |
222 | #ifndef g_assert_true |
223 | #define g_assert_true(expr) \ | |
224 | do { \ | |
225 | if (G_LIKELY(expr)) { \ | |
226 | } else { \ | |
227 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
228 | "'" #expr "' should be TRUE"); \ | |
229 | } \ | |
230 | } while (0) | |
231 | #endif | |
232 | ||
233 | #ifndef g_assert_false | |
234 | #define g_assert_false(expr) \ | |
235 | do { \ | |
236 | if (G_LIKELY(!(expr))) { \ | |
237 | } else { \ | |
238 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
239 | "'" #expr "' should be FALSE"); \ | |
240 | } \ | |
241 | } while (0) | |
242 | #endif | |
243 | ||
244 | #ifndef g_assert_null | |
245 | #define g_assert_null(expr) \ | |
246 | do { \ | |
247 | if (G_LIKELY((expr) == NULL)) { \ | |
248 | } else { \ | |
249 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
250 | "'" #expr "' should be NULL"); \ | |
251 | } \ | |
252 | } while (0) | |
253 | #endif | |
254 | ||
255 | #ifndef g_assert_nonnull | |
256 | #define g_assert_nonnull(expr) \ | |
257 | do { \ | |
258 | if (G_LIKELY((expr) != NULL)) { \ | |
259 | } else { \ | |
260 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
261 | "'" #expr "' should not be NULL"); \ | |
262 | } \ | |
263 | } while (0) | |
264 | #endif | |
265 | ||
266 | #ifndef g_assert_cmpmem | |
267 | #define g_assert_cmpmem(m1, l1, m2, l2) \ | |
268 | do { \ | |
269 | gconstpointer __m1 = m1, __m2 = m2; \ | |
270 | int __l1 = l1, __l2 = l2; \ | |
271 | if (__l1 != __l2) { \ | |
272 | g_assertion_message_cmpnum( \ | |
273 | G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
274 | #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", \ | |
275 | __l2, 'i'); \ | |
276 | } else if (memcmp(__m1, __m2, __l1) != 0) { \ | |
277 | g_assertion_message(G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ | |
278 | "assertion failed (" #m1 " == " #m2 ")"); \ | |
279 | } \ | |
280 | } while (0) | |
281 | #endif | |
282 | ||
5c7e3e9f MAL |
283 | #if !GLIB_CHECK_VERSION(2, 28, 0) |
284 | static inline void g_list_free_full(GList *list, GDestroyNotify free_func) | |
285 | { | |
286 | GList *l; | |
287 | ||
288 | for (l = list; l; l = l->next) { | |
289 | free_func(l->data); | |
290 | } | |
291 | ||
292 | g_list_free(list); | |
293 | } | |
294 | ||
295 | static inline void g_slist_free_full(GSList *list, GDestroyNotify free_func) | |
296 | { | |
297 | GSList *l; | |
298 | ||
299 | for (l = list; l; l = l->next) { | |
300 | free_func(l->data); | |
301 | } | |
302 | ||
303 | g_slist_free(list); | |
304 | } | |
305 | #endif | |
306 | ||
d63c9477 | 307 | #endif |