]>
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 | ||
86946a2d MT |
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 | { | |
f20f2a1f | 83 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
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 | { | |
f20f2a1f | 123 | g_assert(cond->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
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 | { | |
f20f2a1f | 132 | g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS); |
86946a2d MT |
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 | ||
d63c9477 | 168 | #endif |