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 #if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) 28 #error "Only <glib.h> can be included directly." 29 #endif 30 31 #ifndef __G_THREAD_H__ 32 #define __G_THREAD_H__ 33 34 #include <glib/gerror.h> 35 #include <glib/gtypes.h> 36 #include <glib/gutils.h> /* for G_INLINE_FUNC */ 37 #include <glib/gatomic.h> /* for g_atomic_pointer_get */ 38 39 G_BEGIN_DECLS 40 41 /* GLib Thread support 42 */ 43 44 extern GQuark g_thread_error_quark (void); 45 #define G_THREAD_ERROR g_thread_error_quark () 46 47 typedef enum 48 { 49 G_THREAD_ERROR_AGAIN /* Resource temporarily unavailable */ 50 } GThreadError; 51 52 typedef gpointer (*GThreadFunc) (gpointer data); 53 54 typedef enum 55 { 56 G_THREAD_PRIORITY_LOW, 57 G_THREAD_PRIORITY_NORMAL, 58 G_THREAD_PRIORITY_HIGH, 59 G_THREAD_PRIORITY_URGENT 60 } GThreadPriority; 61 62 typedef struct _GThread GThread; 63 struct _GThread 64 { 65 /*< private >*/ 66 GThreadFunc func; 67 gpointer data; 68 gboolean joinable; 69 GThreadPriority priority; 70 }; 71 72 typedef struct _GMutex GMutex; 73 typedef struct _GCond GCond; 74 typedef struct _GPrivate GPrivate; 75 typedef struct _GStaticPrivate GStaticPrivate; 76 77 typedef struct _GThreadFunctions GThreadFunctions; 78 struct _GThreadFunctions 79 { 80 GMutex* (*mutex_new) (void); 81 void (*mutex_lock) (GMutex *mutex); 82 gboolean (*mutex_trylock) (GMutex *mutex); 83 void (*mutex_unlock) (GMutex *mutex); 84 void (*mutex_free) (GMutex *mutex); 85 GCond* (*cond_new) (void); 86 void (*cond_signal) (GCond *cond); 87 void (*cond_broadcast) (GCond *cond); 88 void (*cond_wait) (GCond *cond, 89 GMutex *mutex); 90 gboolean (*cond_timed_wait) (GCond *cond, 91 GMutex *mutex, 92 GTimeVal *end_time); 93 void (*cond_free) (GCond *cond); 94 GPrivate* (*private_new) (GDestroyNotify destructor); 95 gpointer (*private_get) (GPrivate *private_key); 96 void (*private_set) (GPrivate *private_key, 97 gpointer data); 98 void (*thread_create) (GThreadFunc func, 99 gpointer data, 100 gulong stack_size, 101 gboolean joinable, 102 gboolean bound, 103 GThreadPriority priority, 104 gpointer thread, 105 GError **error); 106 void (*thread_yield) (void); 107 void (*thread_join) (gpointer thread); 108 void (*thread_exit) (void); 109 void (*thread_set_priority)(gpointer thread, 110 GThreadPriority priority); 111 void (*thread_self) (gpointer thread); 112 gboolean (*thread_equal) (gpointer thread1, 113 gpointer thread2); 114 }; 115 116 GLIB_VAR GThreadFunctions g_thread_functions_for_glib_use; 117 GLIB_VAR gboolean g_thread_use_default_impl; 118 GLIB_VAR gboolean g_threads_got_initialized; 119 120 GLIB_VAR guint64 (*g_thread_gettime) (void); 121 122 /* initializes the mutex/cond/private implementation for glib, might 123 * only be called once, and must not be called directly or indirectly 124 * from another glib-function, e.g. as a callback. 125 */ 126 void g_thread_init (GThreadFunctions *vtable); 127 128 /* Errorcheck mutexes. If you define G_ERRORCHECK_MUTEXES, then all 129 * mutexes will check for re-locking and re-unlocking */ 130 131 /* Initialize thread system with errorcheck mutexes. vtable must be 132 * NULL. Do not call directly. Use #define G_ERRORCHECK_MUTEXES 133 * instead. 134 */ 135 void g_thread_init_with_errorcheck_mutexes (GThreadFunctions* vtable); 136 137 /* Checks if thread support is initialized. Identical to the 138 * g_thread_supported macro but provided for language bindings. 139 */ 140 gboolean g_thread_get_initialized (void); 141 142 /* A random number to recognize debug calls to g_mutex_... */ 143 #define G_MUTEX_DEBUG_MAGIC 0xf8e18ad7 144 145 #ifdef G_ERRORCHECK_MUTEXES 146 #define g_thread_init(vtable) g_thread_init_with_errorcheck_mutexes (vtable) 147 #endif 148 149 /* internal function for fallback static mutex implementation */ 150 GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex); 151 152 #define g_static_mutex_get_mutex_impl_shortcut(mutex) \ 153 (g_atomic_pointer_get (mutex) ? *(mutex) : \ 154 g_static_mutex_get_mutex_impl (mutex)) 155 156 /* shorthands for conditional and unconditional function calls */ 157 158 #define G_THREAD_UF(op, arglist) \ 159 (*g_thread_functions_for_glib_use . op) arglist 160 #define G_THREAD_CF(op, fail, arg) \ 161 (g_thread_supported () ? G_THREAD_UF (op, arg) : (fail)) 162 #define G_THREAD_ECF(op, fail, mutex, type) \ 163 (g_thread_supported () ? \ 164 ((type(*)(GMutex*, const gulong, gchar const*)) \ 165 (*g_thread_functions_for_glib_use . op)) \ 166 (mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (fail)) 167 168 #ifndef G_ERRORCHECK_MUTEXES 169 # define g_mutex_lock(mutex) \ 170 G_THREAD_CF (mutex_lock, (void)0, (mutex)) 171 # define g_mutex_trylock(mutex) \ 172 G_THREAD_CF (mutex_trylock, TRUE, (mutex)) 173 # define g_mutex_unlock(mutex) \ 174 G_THREAD_CF (mutex_unlock, (void)0, (mutex)) 175 # define g_mutex_free(mutex) \ 176 G_THREAD_CF (mutex_free, (void)0, (mutex)) 177 # define g_cond_wait(cond, mutex) \ 178 G_THREAD_CF (cond_wait, (void)0, (cond, mutex)) 179 # define g_cond_timed_wait(cond, mutex, abs_time) \ 180 G_THREAD_CF (cond_timed_wait, TRUE, (cond, mutex, abs_time)) 181 #else /* G_ERRORCHECK_MUTEXES */ 182 # define g_mutex_lock(mutex) \ 183 G_THREAD_ECF (mutex_lock, (void)0, (mutex), void) 184 # define g_mutex_trylock(mutex) \ 185 G_THREAD_ECF (mutex_trylock, TRUE, (mutex), gboolean) 186 # define g_mutex_unlock(mutex) \ 187 G_THREAD_ECF (mutex_unlock, (void)0, (mutex), void) 188 # define g_mutex_free(mutex) \ 189 G_THREAD_ECF (mutex_free, (void)0, (mutex), void) 190 # define g_cond_wait(cond, mutex) \ 191 (g_thread_supported () ? ((void(*)(GCond*, GMutex*, gulong, gchar*))\ 192 g_thread_functions_for_glib_use.cond_wait) \ 193 (cond, mutex, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : (void) 0) 194 # define g_cond_timed_wait(cond, mutex, abs_time) \ 195 (g_thread_supported () ? \ 196 ((gboolean(*)(GCond*, GMutex*, GTimeVal*, gulong, gchar*)) \ 197 g_thread_functions_for_glib_use.cond_timed_wait) \ 198 (cond, mutex, abs_time, G_MUTEX_DEBUG_MAGIC, G_STRLOC) : TRUE) 199 #endif /* G_ERRORCHECK_MUTEXES */ 200 201 #define g_thread_supported() (g_threads_got_initialized) 202 #define g_mutex_new() G_THREAD_UF (mutex_new, ()) 203 #define g_cond_new() G_THREAD_UF (cond_new, ()) 204 #define g_cond_signal(cond) G_THREAD_CF (cond_signal, (void)0, (cond)) 205 #define g_cond_broadcast(cond) G_THREAD_CF (cond_broadcast, (void)0, (cond)) 206 #define g_cond_free(cond) G_THREAD_CF (cond_free, (void)0, (cond)) 207 #define g_private_new(destructor) G_THREAD_UF (private_new, (destructor)) 208 #define g_private_get(private_key) G_THREAD_CF (private_get, \ 209 ((gpointer)private_key), \ 210 (private_key)) 211 #define g_private_set(private_key, value) G_THREAD_CF (private_set, \ 212 (void) (private_key = \ 213 (GPrivate*) (value)), \ 214 (private_key, value)) 215 #define g_thread_yield() G_THREAD_CF (thread_yield, (void)0, ()) 216 217 #define g_thread_create(func, data, joinable, error) \ 218 (g_thread_create_full (func, data, 0, joinable, FALSE, \ 219 G_THREAD_PRIORITY_NORMAL, error)) 220 221 GThread* g_thread_create_full (GThreadFunc func, 222 gpointer data, 223 gulong stack_size, 224 gboolean joinable, 225 gboolean bound, 226 GThreadPriority priority, 227 GError **error); 228 GThread* g_thread_self (void); 229 void g_thread_exit (gpointer retval); 230 gpointer g_thread_join (GThread *thread); 231 232 void g_thread_set_priority (GThread *thread, 233 GThreadPriority priority); 234 235 /* GStaticMutexes can be statically initialized with the value 236 * G_STATIC_MUTEX_INIT, and then they can directly be used, that is 237 * much easier, than having to explicitly allocate the mutex before 238 * use 239 */ 240 #define g_static_mutex_lock(mutex) \ 241 g_mutex_lock (g_static_mutex_get_mutex (mutex)) 242 #define g_static_mutex_trylock(mutex) \ 243 g_mutex_trylock (g_static_mutex_get_mutex (mutex)) 244 #define g_static_mutex_unlock(mutex) \ 245 g_mutex_unlock (g_static_mutex_get_mutex (mutex)) 246 void g_static_mutex_init (GStaticMutex *mutex); 247 void g_static_mutex_free (GStaticMutex *mutex); 248 249 struct _GStaticPrivate 250 { 251 /*< private >*/ 252 guint index; 253 }; 254 #define G_STATIC_PRIVATE_INIT { 0 } 255 void g_static_private_init (GStaticPrivate *private_key); 256 gpointer g_static_private_get (GStaticPrivate *private_key); 257 void g_static_private_set (GStaticPrivate *private_key, 258 gpointer data, 259 GDestroyNotify notify); 260 void g_static_private_free (GStaticPrivate *private_key); 261 262 typedef struct _GStaticRecMutex GStaticRecMutex; 263 struct _GStaticRecMutex 264 { 265 /*< private >*/ 266 GStaticMutex mutex; 267 guint depth; 268 GSystemThread owner; 269 }; 270 271 #define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT } 272 void g_static_rec_mutex_init (GStaticRecMutex *mutex); 273 void g_static_rec_mutex_lock (GStaticRecMutex *mutex); 274 gboolean g_static_rec_mutex_trylock (GStaticRecMutex *mutex); 275 void g_static_rec_mutex_unlock (GStaticRecMutex *mutex); 276 void g_static_rec_mutex_lock_full (GStaticRecMutex *mutex, 277 guint depth); 278 guint g_static_rec_mutex_unlock_full (GStaticRecMutex *mutex); 279 void g_static_rec_mutex_free (GStaticRecMutex *mutex); 280 281 typedef struct _GStaticRWLock GStaticRWLock; 282 struct _GStaticRWLock 283 { 284 /*< private >*/ 285 GStaticMutex mutex; 286 GCond *read_cond; 287 GCond *write_cond; 288 guint read_counter; 289 gboolean have_writer; 290 guint want_to_read; 291 guint want_to_write; 292 }; 293 294 #define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, 0, 0 } 295 296 void g_static_rw_lock_init (GStaticRWLock* lock); 297 void g_static_rw_lock_reader_lock (GStaticRWLock* lock); 298 gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock); 299 void g_static_rw_lock_reader_unlock (GStaticRWLock* lock); 300 void g_static_rw_lock_writer_lock (GStaticRWLock* lock); 301 gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock); 302 void g_static_rw_lock_writer_unlock (GStaticRWLock* lock); 303 void g_static_rw_lock_free (GStaticRWLock* lock); 304 305 void g_thread_foreach (GFunc thread_func, 306 gpointer user_data); 307 308 typedef enum 309 { 310 G_ONCE_STATUS_NOTCALLED, 311 G_ONCE_STATUS_PROGRESS, 312 G_ONCE_STATUS_READY 313 } GOnceStatus; 314 315 typedef struct _GOnce GOnce; 316 struct _GOnce 317 { 318 volatile GOnceStatus status; 319 volatile gpointer retval; 320 }; 321 322 #define G_ONCE_INIT { G_ONCE_STATUS_NOTCALLED, NULL } 323 324 gpointer g_once_impl (GOnce *once, GThreadFunc func, gpointer arg); 325 326 #ifdef G_ATOMIC_OP_MEMORY_BARRIER_NEEDED 327 # define g_once(once, func, arg) g_once_impl ((once), (func), (arg)) 328 #else /* !G_ATOMIC_OP_MEMORY_BARRIER_NEEDED*/ 329 # define g_once(once, func, arg) \ 330 (((once)->status == G_ONCE_STATUS_READY) ? \ 331 (once)->retval : \ 332 g_once_impl ((once), (func), (arg))) 333 #endif /* G_ATOMIC_OP_MEMORY_BARRIER_NEEDED */ 334 335 /* initialize-once guards, keyed by value_location */ 336 G_INLINE_FUNC gboolean g_once_init_enter (volatile gsize *value_location); 337 gboolean g_once_init_enter_impl (volatile gsize *value_location); 338 void g_once_init_leave (volatile gsize *value_location, 339 gsize initialization_value); 340 #if defined (G_CAN_INLINE) || defined (__G_THREAD_C__) 341 G_INLINE_FUNC gboolean 342 g_once_init_enter (volatile gsize *value_location) 343 { 344 if G_LIKELY ((gpointer) g_atomic_pointer_get (value_location) != NULL) 345 return FALSE; 346 else 347 return g_once_init_enter_impl (value_location); 348 } 349 #endif /* G_CAN_INLINE || __G_THREAD_C__ */ 350 351 /* these are some convenience macros that expand to nothing if GLib 352 * was configured with --disable-threads. for using StaticMutexes, 353 * you define them with G_LOCK_DEFINE_STATIC (name) or G_LOCK_DEFINE (name) 354 * if you need to export the mutex. With G_LOCK_EXTERN (name) you can 355 * declare such an globally defined lock. name is a unique identifier 356 * for the protected varibale or code portion. locking, testing and 357 * unlocking of such mutexes can be done with G_LOCK(), G_UNLOCK() and 358 * G_TRYLOCK() respectively. 359 */ 360 extern void glib_dummy_decl (void); 361 #define G_LOCK_NAME(name) g__ ## name ## _lock 362 #ifdef G_THREADS_ENABLED 363 # define G_LOCK_DEFINE_STATIC(name) static G_LOCK_DEFINE (name) 364 # define G_LOCK_DEFINE(name) \ 365 GStaticMutex G_LOCK_NAME (name) = G_STATIC_MUTEX_INIT 366 # define G_LOCK_EXTERN(name) extern GStaticMutex G_LOCK_NAME (name) 367 368 # ifdef G_DEBUG_LOCKS 369 # define G_LOCK(name) G_STMT_START{ \ 370 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ 371 "file %s: line %d (%s): locking: %s ", \ 372 __FILE__, __LINE__, G_STRFUNC, \ 373 #name); \ 374 g_static_mutex_lock (&G_LOCK_NAME (name)); \ 375 }G_STMT_END 376 # define G_UNLOCK(name) G_STMT_START{ \ 377 g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ 378 "file %s: line %d (%s): unlocking: %s ", \ 379 __FILE__, __LINE__, G_STRFUNC, \ 380 #name); \ 381 g_static_mutex_unlock (&G_LOCK_NAME (name)); \ 382 }G_STMT_END 383 # define G_TRYLOCK(name) \ 384 (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \ 385 "file %s: line %d (%s): try locking: %s ", \ 386 __FILE__, __LINE__, G_STRFUNC, \ 387 #name), g_static_mutex_trylock (&G_LOCK_NAME (name))) 388 # else /* !G_DEBUG_LOCKS */ 389 # define G_LOCK(name) g_static_mutex_lock (&G_LOCK_NAME (name)) 390 # define G_UNLOCK(name) g_static_mutex_unlock (&G_LOCK_NAME (name)) 391 # define G_TRYLOCK(name) g_static_mutex_trylock (&G_LOCK_NAME (name)) 392 # endif /* !G_DEBUG_LOCKS */ 393 #else /* !G_THREADS_ENABLED */ 394 # define G_LOCK_DEFINE_STATIC(name) extern void glib_dummy_decl (void) 395 # define G_LOCK_DEFINE(name) extern void glib_dummy_decl (void) 396 # define G_LOCK_EXTERN(name) extern void glib_dummy_decl (void) 397 # define G_LOCK(name) 398 # define G_UNLOCK(name) 399 # define G_TRYLOCK(name) (TRUE) 400 #endif /* !G_THREADS_ENABLED */ 401 402 G_END_DECLS 403 404 #endif /* __G_THREAD_H__ */ 405