1 | /* GLIB - Library of useful routines for C programming |
---|
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
---|
3 | * |
---|
4 | * This library is free software; you can redistribute it and/or |
---|
5 | * modify it under the terms of the GNU Lesser General Public |
---|
6 | * License as published by the Free Software Foundation; either |
---|
7 | * version 2 of the License, or (at your option) any later version. |
---|
8 | * |
---|
9 | * This library is distributed in the hope that it will be useful, |
---|
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | * Lesser General Public License for more details. |
---|
13 | * |
---|
14 | * You should have received a copy of the GNU Lesser General Public |
---|
15 | * License along with this library; if not, write to the |
---|
16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
17 | * Boston, MA 02111-1307, USA. |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
21 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
---|
22 | * file for a list of people on the GLib Team. See the ChangeLog |
---|
23 | * files for a list of changes. These files are distributed with |
---|
24 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
---|
25 | */ |
---|
26 | |
---|
27 | #ifndef __G_THREAD_H__ |
---|
28 | #define __G_THREAD_H__ |
---|
29 | |
---|
30 | #include <glib/gerror.h> |
---|
31 | #include <glib/gtypes.h> |
---|
32 | #include <glib/gatomic.h> /* for g_atomic_pointer_get */ |
---|
33 | |
---|
34 | G_BEGIN_DECLS |
---|
35 | |
---|
36 | /* GLib Thread support |
---|
37 | */ |
---|
38 | |
---|
39 | extern GQuark g_thread_error_quark (void); |
---|
40 | #define G_THREAD_ERROR g_thread_error_quark () |
---|
41 | |
---|
42 | typedef enum |
---|
43 | { |
---|
44 | G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */ |
---|
45 | } GThreadError; |
---|
46 | |
---|
47 | typedef gpointer (*GThreadFunc) (gpointer data); |
---|
48 | |
---|
49 | typedef enum |
---|
50 | { |
---|
51 | G_THREAD_PRIORITY_LOW, |
---|
52 | G_THREAD_PRIORITY_NORMAL, |
---|
53 | G_THREAD_PRIORITY_HIGH, |
---|
54 | G_THREAD_PRIORITY_URGENT |
---|
55 | } GThreadPriority; |
---|
56 | |
---|
57 | typedef struct _GThread GThread; |
---|
58 | struct _GThread |
---|
59 | { |
---|
60 | /*< private >*/ |
---|
61 | GThreadFunc func; |
---|
62 | gpointer data; |
---|
63 | gboolean joinable; |
---|
64 | GThreadPriority priority; |
---|
65 | }; |
---|
66 | |
---|
67 | typedef struct _GMutex GMutex; |
---|
68 | typedef struct _GCond GCond; |
---|
69 | typedef struct _GPrivate GPrivate; |
---|
70 | typedef struct _GStaticPrivate GStaticPrivate; |
---|
71 | |
---|
72 | typedef struct _GThreadFunctions GThreadFunctions; |
---|
73 | struct _GThreadFunctions |
---|
74 | { |
---|
75 | GMutex* (*mutex_new) (void); |
---|
76 | void (*mutex_lock) (GMutex *mutex); |
---|
77 | gboolean (*mutex_trylock) (GMutex *mutex); |
---|
78 | void (*mutex_unlock) (GMutex *mutex); |
---|
79 | void (*mutex_free) (GMutex *mutex); |
---|
80 | GCond* (*cond_new) (void); |
---|
81 | void (*cond_signal) (GCond *cond); |
---|
82 | void (*cond_broadcast) (GCond *cond); |
---|
83 | void (*cond_wait) (GCond *cond, |
---|
84 | GMutex *mutex); |
---|
85 | gboolean (*cond_timed_wait) (GCond *cond, |
---|
86 | GMutex *mutex, |
---|
87 | GTimeVal *end_time); |
---|
88 | void (*cond_free) (GCond *cond); |
---|
89 | GPrivate* (*private_new) (GDestroyNotify destructor); |
---|
90 | gpointer (*private_get) (GPrivate *private_key); |
---|
91 | void (*private_set) (GPrivate *private_key, |
---|
92 | gpointer data); |
---|
93 | void (*thread_create) (GThreadFunc func, |
---|
94 | gpointer data, |
---|
95 | gulong stack_size, |
---|
96 | gboolean joinable, |
---|
97 | gboolean bound, |
---|
98 | GThreadPriority priority, |
---|
99 | gpointer thread, |
---|
100 | GError **error); |
---|
101 | void (*thread_yield) (void); |
---|
102 | void (*thread_join) (gpointer thread); |
---|
103 | void (*thread_exit) (void); |
---|
104 | void (*thread_set_priority)(gpointer thread, |
---|
105 | GThreadPriority priority); |
---|
106 | void (*thread_self) (gpointer thread); |
---|
107 | gboolean (*thread_equal) (gpointer thread1, |
---|
108 | gpointer thread2); |
---|
109 | }; |
---|
110 | |
---|
111 | GLIB_VAR GThreadFunctions g_thread_functions_for_glib_use; |
---|
112 | GLIB_VAR gboolean g_thread_use_default_impl; |
---|
113 | GLIB_VAR gboolean g_threads_got_initialized; |
---|
114 | |
---|
115 | /* initializes the mutex/cond/private implementation for glib, might |
---|
116 | * only be called once, and must not be called directly or indirectly |
---|
117 | * from another glib-function, e.g. as a callback. |
---|
118 | */ |
---|
119 | void g_thread_init (GThreadFunctions *vtable); |
---|
120 | |
---|
121 | /* Errorcheck mutexes. If you define G_ERRORCHECK_MUTEXES, then all |
---|
122 | * mutexes will check for re-locking and re-unlocking */ |
---|
123 | |
---|
124 | /* Initialize thread system with errorcheck mutexes. vtable must be |
---|
125 | * NULL. Do not call directly. Use #define G_ERRORCHECK_MUTEXES |
---|
126 | * instead. |
---|
127 | */ |
---|
128 | void g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable); |
---|
129 | |
---|
130 | /* A random number to recognize debug calls to g_mutex_... */ |
---|
131 | #define G_MUTEX_DEBUG_MAGIC 0xf8e18ad7 |
---|
132 | |
---|
133 | #ifdef G_ERRORCHECK_MUTEXES |
---|
134 | #define g_thread_init(vtable) g_thread_init_with_errorcheck_mutexes (vtable) |
---|
135 | #endif |
---|
136 | |
---|
137 | /* internal function for fallback static mutex implementation */ |
---|
138 | GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex); |
---|
139 | |
---|
140 | #define g_static_mutex_get_mutex_impl_shortcut(mutex) \ |
---|
141 | (g_atomic_pointer_get ((gpointer*)mutex) ? *(mutex) : \ |
---|
142 | g_static_mutex_get_mutex_impl (mutex)) |
---|
143 | |
---|
144 | /* shorthands for conditional and unconditional function calls */ |
---|
145 | |
---|
146 | #define G_THREAD_UF(op, arglist) \ |
---|
147 | (*g_thread_functions_for_glib_use . op) arglist |
---|
148 | #define G_THREAD_CF(op, fail, arg) \ |
---|
149 | (g_thread_supported () ? G_THREAD_UF (op, arg) : (fail)) |
---|
150 | #define G_THREAD_ECF(op, fail, mutex, type) \ |
---|
151 | (g_thread_supported () ? ((type(*)(GMutex*, gulong, gchar*)) \ |
---|
152 | (*g_thread_functions_for_glib_use . op)) \ |
---|
153 | (mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (fail)) |
---|
154 | |
---|
155 | #ifndef G_ERRORCHECK_MUTEXES |
---|
156 | # define g_mutex_lock(mutex) \ |
---|
157 | G_THREAD_CF (mutex_lock, (void)0, (mutex)) |
---|
158 | # define g_mutex_trylock(mutex) \ |
---|
159 | G_THREAD_CF (mutex_trylock, TRUE, (mutex)) |
---|
160 | # define g_mutex_unlock(mutex) \ |
---|
161 | G_THREAD_CF (mutex_unlock, (void)0, (mutex)) |
---|
162 | # define g_mutex_free(mutex) \ |
---|
163 | G_THREAD_CF (mutex_free, (void)0, (mutex)) |
---|
164 | # define g_cond_wait(cond, mutex) \ |
---|
165 | G_THREAD_CF (cond_wait, (void)0, (cond, mutex)) |
---|
166 | # define g_cond_timed_wait(cond, mutex, abs_time) \ |
---|
167 | G_THREAD_CF (cond_timed_wait, TRUE, (cond, mutex, abs_time)) |
---|
168 | #else /* G_ERRORCHECK_MUTEXES */ |
---|
169 | # define g_mutex_lock(mutex) \ |
---|
170 | G_THREAD_ECF (mutex_lock, (void)0, (mutex), void) |
---|
171 | # define g_mutex_trylock(mutex) \ |
---|
172 | G_THREAD_ECF (mutex_trylock, TRUE, (mutex), gboolean) |
---|
173 | # define g_mutex_unlock(mutex) \ |
---|
174 | G_THREAD_ECF (mutex_unlock, (void)0, (mutex), void) |
---|
175 | # define g_mutex_free(mutex) \ |
---|
176 | G_THREAD_ECF (mutex_free, (void)0, (mutex), void) |
---|
177 | # define g_cond_wait(cond, mutex) \ |
---|
178 | (g_thread_supported () ? ((void(*)(GCond*, GMutex*, gulong, gchar*))\ |
---|
179 | g_thread_functions_for_glib_use.cond_wait) \ |
---|
180 | (cond, mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (void) 0) |
---|
181 | # define g_cond_timed_wait(cond, mutex, abs_time) \ |
---|
182 | (g_thread_supported () ? \ |
---|
183 | ((gboolean(*)(GCond*, GMutex*, GTimeVal*, gulong, gchar*)) \ |
---|
184 | g_thread_functions_for_glib_use.cond_timed_wait) \ |
---|
185 | (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE) |
---|
186 | #endif /* G_ERRORCHECK_MUTEXES */ |
---|
187 | |
---|
188 | #define g_thread_supported() (g_threads_got_initialized) |
---|
189 | #define g_mutex_new() G_THREAD_UF (mutex_new, ()) |
---|
190 | #define g_cond_new() G_THREAD_UF (cond_new, ()) |
---|
191 | #define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond)) |
---|
192 | #define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond)) |
---|
193 | #define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond)) |
---|
194 | #define g_private_new(destructor) G_THREAD_UF (private_new, (destructor)) |
---|
195 | #define g_private_get(private_key) G_THREAD_CF (private_get, \ |
---|
196 | ((gpointer)private_key), \ |
---|
197 | (private_key)) |
---|
198 | #define g_private_set(private_key, value) G_THREAD_CF (private_set, \ |
---|
199 | (void) (private_key = \ |
---|
200 | (GPrivate*) (value)), \ |
---|
201 | (private_key, value)) |
---|
202 | #define g_thread_yield() G_THREAD_CF (thread_yield, (void)0, ()) |
---|
203 | |
---|
204 | #define g_thread_create(func, data, joinable, error) \ |
---|
205 | (g_thread_create_full (func, data, 0, joinable, FALSE, \ |
---|
206 | G_THREAD_PRIORITY_NORMAL, error)) |
---|
207 | |
---|
208 | GThread* g_thread_create_full (GThreadFunc func, |
---|
209 | gpointer data, |
---|
210 | gulong stack_size, |
---|
211 | gboolean joinable, |
---|
212 | gboolean bound, |
---|
213 | GThreadPriority priority, |
---|
214 | GError **error); |
---|
215 | GThread* g_thread_self (void); |
---|
216 | void g_thread_exit (gpointer retval); |
---|
217 | gpointer g_thread_join (GThread *thread); |
---|
218 | |
---|
219 | void g_thread_set_priority (GThread *thread, |
---|
220 | GThreadPriority priority); |
---|
221 | |
---|
222 | /* GStaticMutexes can be statically initialized with the value |
---|
223 | * G_STATIC_MUTEX_INIT, and then they can directly be used, that is |
---|
224 | * much easier, than having to explicitly allocate the mutex before |
---|
225 | * use |
---|
226 | */ |
---|
227 | #define g_static_mutex_lock(mutex) \ |
---|
228 | g_mutex_lock (g_static_mutex_get_mutex (mutex)) |
---|
229 | #define g_static_mutex_trylock(mutex) \ |
---|
230 | g_mutex_trylock (g_static_mutex_get_mutex (mutex)) |
---|
231 | #define g_static_mutex_unlock(mutex) \ |
---|
232 | g_mutex_unlock (g_static_mutex_get_mutex (mutex)) |
---|
233 | void g_static_mutex_init (GStaticMutex *mutex); |
---|
234 | void g_static_mutex_free (GStaticMutex *mutex); |
---|
235 | |
---|
236 | struct _GStaticPrivate |
---|
237 | { |
---|
238 | /*< private >*/ |
---|
239 | guint index; |
---|
240 | }; |
---|
241 | #define G_STATIC_PRIVATE_INIT { 0 } |
---|
242 | void g_static_private_init (GStaticPrivate *private_key); |
---|
243 | gpointer g_static_private_get (GStaticPrivate *private_key); |
---|
244 | void g_static_private_set (GStaticPrivate *private_key, |
---|
245 | gpointer data, |
---|
246 | GDestroyNotify notify); |
---|
247 | void g_static_private_free (GStaticPrivate *private_key); |
---|
248 | |
---|
249 | typedef struct _GStaticRecMutex GStaticRecMutex; |
---|
250 | struct _GStaticRecMutex |
---|
251 | { |
---|
252 | /*< private >*/ |
---|
253 | GStaticMutex mutex; |
---|
254 | guint depth; |
---|
255 | GSystemThread owner; |
---|
256 | }; |
---|
257 | |
---|
258 | #define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT } |
---|
259 | void g_static_rec_mutex_init (GStaticRecMutex *mutex); |
---|
260 | void g_static_rec_mutex_lock (GStaticRecMutex *mutex); |
---|
261 | gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex); |
---|
262 | void g_static_rec_mutex_unlock (GStaticRecMutex *mutex); |
---|
263 | void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, |
---|
264 | guint depth); |
---|
265 | guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex); |
---|
266 | void g_static_rec_mutex_free (GStaticRecMutex *mutex); |
---|
267 | |
---|
268 | typedef struct _GStaticRWLock GStaticRWLock; |
---|
269 | struct _GStaticRWLock |
---|
270 | { |
---|
271 | /*< private >*/ |
---|
272 | GStaticMutex mutex; |
---|
273 | GCond *read_cond; |
---|
274 | GCond *write_cond; |
---|
275 | guint read_counter; |
---|
276 | gboolean have_writer; |
---|
277 | guint want_to_read; |
---|
278 | guint want_to_write; |
---|
279 | }; |
---|
280 | |
---|
281 | #define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 } |
---|
282 | |
---|
283 | void g_static_rw_lock_init (GStaticRWLock* lock); |
---|
284 | void g_static_rw_lock_reader_lock (GStaticRWLock* lock); |
---|
285 | gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock); |
---|
286 | void g_static_rw_lock_reader_unlock (GStaticRWLock* lock); |
---|
287 | void g_static_rw_lock_writer_lock (GStaticRWLock* lock); |
---|
288 | gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock); |
---|
289 | void g_static_rw_lock_writer_unlock (GStaticRWLock* lock); |
---|
290 | void g_static_rw_lock_free (GStaticRWLock* lock); |
---|
291 | |
---|
292 | typedef enum |
---|
293 | { |
---|
294 | G_ONCE_STATUS_NOTCALLED, |
---|
295 | G_ONCE_STATUS_PROGRESS, |
---|
296 | G_ONCE_STATUS_READY |
---|
297 | } GOnceStatus; |
---|
298 | |
---|
299 | typedef struct _GOnce GOnce; |
---|
300 | struct _GOnce |
---|
301 | { |
---|
302 | volatile GOnceStatus status; |
---|
303 | volatile gpointer retval; |
---|
304 | }; |
---|
305 | |
---|
306 | #define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL } |
---|
307 | |
---|
308 | gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg); |
---|
309 | |
---|
310 | #ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED |
---|
311 | # define g_once(once, func, arg) g_once_impl ((once), (func), (arg)) |
---|
312 | #else /* !G_ATOMIC_OP_MEMORY_BARRIER_NEEDED*/ |
---|
313 | # define g_once(once, func, arg) \ |
---|
314 | (((once)->status == G_ONCE_STATUS_READY) ? \ |
---|
315 | (once)->retval : \ |
---|
316 | g_once_impl ((once), (func), (arg))) |
---|
317 | #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ |
---|
318 | |
---|
319 | /* these are some convenience macros that expand to nothing if GLib |
---|
320 | * was configured with --disable-threads. for using StaticMutexes, |
---|
321 | * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name) |
---|
322 | * if you need to export the mutex. With G_LOCK_EXTERN (name) you can |
---|
323 | * declare such an globally defined lock. name is a unique identifier |
---|
324 | * for the protected varibale or code portion. locking, testing and |
---|
325 | * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and |
---|
326 | * G_TRYLOCK() respectively. |
---|
327 | */ |
---|
328 | extern void glib_dummy_decl (void); |
---|
329 | #define G_LOCK_NAME(name) g__ ## name ## _lock |
---|
330 | #ifdef G_THREADS_ENABLED |
---|
331 | # define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name) |
---|
332 | # define G_LOCK_DEFINE(name) \ |
---|
333 | GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT |
---|
334 | # define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name) |
---|
335 | |
---|
336 | # ifdef G_DEBUG_LOCKS |
---|
337 | # define G_LOCK(name) G_STMT_START{ \ |
---|
338 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ |
---|
339 | "file %s: line %d (%s): locking: %s ", \ |
---|
340 | __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ |
---|
341 | #name); \ |
---|
342 | g_static_mutex_lock (&G_LOCK_NAME (name)); \ |
---|
343 | }G_STMT_END |
---|
344 | # define G_UNLOCK(name) G_STMT_START{ \ |
---|
345 | g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ |
---|
346 | "file %s: line %d (%s): unlocking: %s ", \ |
---|
347 | __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ |
---|
348 | #name); \ |
---|
349 | g_static_mutex_unlock (&G_LOCK_NAME (name)); \ |
---|
350 | }G_STMT_END |
---|
351 | # define G_TRYLOCK(name) \ |
---|
352 | (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ |
---|
353 | "file %s: line %d (%s): try locking: %s ", \ |
---|
354 | __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION, \ |
---|
355 | #name), g_static_mutex_trylock (&G_LOCK_NAME (name))) |
---|
356 | # else /* !G_DEBUG_LOCKS */ |
---|
357 | # define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name)) |
---|
358 | # define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name)) |
---|
359 | # define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name)) |
---|
360 | # endif /* !G_DEBUG_LOCKS */ |
---|
361 | #else /* !G_THREADS_ENABLED */ |
---|
362 | # define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void) |
---|
363 | # define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void) |
---|
364 | # define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void) |
---|
365 | # define G_LOCK(name) |
---|
366 | # define G_UNLOCK(name) |
---|
367 | # define G_TRYLOCK(name) (TRUE) |
---|
368 | #endif /* !G_THREADS_ENABLED */ |
---|
369 | |
---|
370 | G_END_DECLS |
---|
371 | |
---|
372 | #endif /* __G_THREAD_H__ */ |
---|
373 | |
---|