1 /* GLIB - Library of useful routines for C programming 2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 3 * 4 * gthread.c: thread related functions 5 * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the 19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 21 */ 22 23 /* 24 * Modified by the GLib Team and others 1997-2000. See the AUTHORS 25 * file for a list of people on the GLib Team. See the ChangeLog 26 * files for a list of changes. These files are distributed with 27 * GLib at ftp://ftp.gtk.org/pub/gtk/. 28 */ 29 30 /* 31 * MT safe 32 */ 33 34 #include "config.h" 35 36 #include "glib.h" 37 #include "gthreadprivate.h" 38 39 #ifdef G_THREADS_ENABLED 40 41 static GSystemThread zero_thread; /* This is initialized to all zero */ 42 static gboolean thread_system_already_initialized = FALSE; 43 static gint g_thread_priority_map [G_THREAD_PRIORITY_URGENT + 1]; 44 45 #include G_THREAD_SOURCE 46 47 #ifndef PRIORITY_LOW_VALUE 48 # define PRIORITY_LOW_VALUE 0 49 #endif 50 51 #ifndef PRIORITY_URGENT_VALUE 52 # define PRIORITY_URGENT_VALUE 0 53 #endif 54 55 #ifndef PRIORITY_NORMAL_VALUE 56 # define PRIORITY_NORMAL_VALUE \ 57 ((PRIORITY_LOW_VALUE * 6 + PRIORITY_URGENT_VALUE * 4) / 10) 58 #endif /* PRIORITY_NORMAL_VALUE */ 59 60 #ifndef PRIORITY_HIGH_VALUE 61 # define PRIORITY_HIGH_VALUE \ 62 ((PRIORITY_NORMAL_VALUE + PRIORITY_URGENT_VALUE * 2) / 3) 63 #endif /* PRIORITY_HIGH_VALUE */ 64 65 void g_mutex_init (void); 66 void g_mem_init (void); 67 void g_messages_init (void); 68 void g_convert_init (void); 69 void g_rand_init (void); 70 void g_main_thread_init (void); 71 72 typedef struct _GMutexDebugInfo GMutexDebugInfo; 73 struct _GMutexDebugInfo 74 { 75 gchar *location; 76 GSystemThread owner; 77 }; 78 79 #define G_MUTEX_DEBUG_INFO(mutex) \ 80 (((GMutexDebugInfo*)(((char*)mutex)+G_MUTEX_SIZE))) 81 82 static GMutex * 83 g_mutex_new_errorcheck_impl (void) 84 { 85 GMutex *retval = g_thread_functions_for_glib_use_default.mutex_new (); 86 GMutexDebugInfo *info; 87 retval = g_realloc (retval, G_MUTEX_SIZE + sizeof (GMutexDebugInfo)); 88 89 info = G_MUTEX_DEBUG_INFO (retval); 90 g_system_thread_assign (info->owner, zero_thread); 91 info->location = "invalid"; 92 93 return retval; 94 } 95 96 static void 97 g_mutex_lock_errorcheck_impl (GMutex *mutex, 98 const gulong magic, 99 gchar * const location) 100 { 101 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 102 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 103 104 GSystemThread self; 105 g_thread_functions_for_glib_use.thread_self (&self); 106 107 if (g_system_thread_equal (info->owner, self)) 108 g_error ("Trying to recursivly lock a mutex at '%s', " 109 "previously locked at '%s'", 110 loc, info->location); 111 112 g_thread_functions_for_glib_use_default.mutex_lock (mutex); 113 114 g_system_thread_assign (info->owner, self); 115 info->location = loc; 116 } 117 118 static gboolean 119 g_mutex_trylock_errorcheck_impl (GMutex *mutex, 120 const gulong magic, 121 gchar * const location) 122 { 123 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 124 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 125 126 GSystemThread self; 127 g_thread_functions_for_glib_use.thread_self (&self); 128 129 if (g_system_thread_equal (info->owner, self)) 130 g_error ("Trying to recursivly lock a mutex at '%s', " 131 "previously locked at '%s'", 132 loc, info->location); 133 134 if (!g_thread_functions_for_glib_use_default.mutex_trylock (mutex)) 135 return FALSE; 136 137 g_system_thread_assign (info->owner, self); 138 info->location = loc; 139 140 return TRUE; 141 } 142 143 static void 144 g_mutex_unlock_errorcheck_impl (GMutex *mutex, 145 const gulong magic, 146 gchar * const location) 147 { 148 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 149 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 150 151 GSystemThread self; 152 g_thread_functions_for_glib_use.thread_self (&self); 153 154 if (g_system_thread_equal (info->owner, zero_thread)) 155 g_error ("Trying to unlock an unlocked mutex at '%s'", loc); 156 157 if (!g_system_thread_equal (info->owner, self)) 158 g_warning ("Trying to unlock a mutex at '%s', " 159 "previously locked by a different thread at '%s'", 160 loc, info->location); 161 162 g_system_thread_assign (info->owner, zero_thread); 163 info->location = NULL; 164 165 g_thread_functions_for_glib_use_default.mutex_unlock (mutex); 166 } 167 168 static void 169 g_mutex_free_errorcheck_impl (GMutex *mutex, 170 const gulong magic, 171 gchar * const location) 172 { 173 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 174 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 175 176 if (info && !g_system_thread_equal (info->owner, zero_thread)) 177 g_error ("Trying to free a locked mutex at '%s', " 178 "which was previously locked at '%s'", 179 loc, info->location); 180 181 g_thread_functions_for_glib_use_default.mutex_free (mutex); 182 } 183 184 static void 185 g_cond_wait_errorcheck_impl (GCond *cond, 186 GMutex *mutex, 187 const gulong magic, 188 gchar * const location) 189 { 190 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 191 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 192 193 GSystemThread self; 194 g_thread_functions_for_glib_use.thread_self (&self); 195 196 if (g_system_thread_equal (info->owner, zero_thread)) 197 g_error ("Trying to use an unlocked mutex in g_cond_wait() at '%s'", loc); 198 199 if (!g_system_thread_equal (info->owner, self)) 200 g_error ("Trying to use a mutex locked by another thread in " 201 "g_cond_wait() at '%s'", loc); 202 203 g_system_thread_assign (info->owner, zero_thread); 204 loc = info->location; 205 206 g_thread_functions_for_glib_use_default.cond_wait (cond, mutex); 207 208 g_system_thread_assign (info->owner, self); 209 info->location = loc; 210 } 211 212 213 static gboolean 214 g_cond_timed_wait_errorcheck_impl (GCond *cond, 215 GMutex *mutex, 216 GTimeVal *end_time, 217 const gulong magic, 218 gchar * const location) 219 { 220 GMutexDebugInfo *info = G_MUTEX_DEBUG_INFO (mutex); 221 gchar *loc = (magic == G_MUTEX_DEBUG_MAGIC) ? location : "unknown"; 222 gboolean retval; 223 224 GSystemThread self; 225 g_thread_functions_for_glib_use.thread_self (&self); 226 227 if (g_system_thread_equal (info->owner, zero_thread)) 228 g_error ("Trying to use an unlocked mutex in g_cond_timed_wait() at '%s'", 229 loc); 230 231 if (!g_system_thread_equal (info->owner, self)) 232 g_error ("Trying to use a mutex locked by another thread in " 233 "g_cond_timed_wait() at '%s'", loc); 234 235 g_system_thread_assign (info->owner, zero_thread); 236 loc = info->location; 237 238 retval = g_thread_functions_for_glib_use_default.cond_timed_wait (cond, 239 mutex, 240 end_time); 241 242 g_system_thread_assign (info->owner, self); 243 info->location = loc; 244 245 return retval; 246 } 247 248 249 /* unshadow function declaration. See gthread.h */ 250 #undef g_thread_init 251 252 void 253 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init) 254 { 255 GThreadFunctions errorcheck_functions; 256 if (init) 257 g_error ("Errorcheck mutexes can only be used for native " 258 "thread implementations. Sorry." ); 259 260 #ifdef HAVE_G_THREAD_IMPL_INIT 261 /* This isn't called in g_thread_init, as it doesn't think to get 262 * the default implementation, so we have to call it on our own. 263 * 264 * We must call this before copying 265 * g_thread_functions_for_glib_use_default as the 266 * implementation-specific init function might modify the contents 267 * of g_thread_functions_for_glib_use_default based on operating 268 * system version, C library version, or whatever. */ 269 g_thread_impl_init(); 270 #endif /* HAVE_G_THREAD_IMPL_INIT */ 271 272 errorcheck_functions = g_thread_functions_for_glib_use_default; 273 errorcheck_functions.mutex_new = g_mutex_new_errorcheck_impl; 274 errorcheck_functions.mutex_lock = 275 (void (*)(GMutex *)) g_mutex_lock_errorcheck_impl; 276 errorcheck_functions.mutex_trylock = 277 (gboolean (*)(GMutex *)) g_mutex_trylock_errorcheck_impl; 278 errorcheck_functions.mutex_unlock = 279 (void (*)(GMutex *)) g_mutex_unlock_errorcheck_impl; 280 errorcheck_functions.mutex_free = 281 (void (*)(GMutex *)) g_mutex_free_errorcheck_impl; 282 errorcheck_functions.cond_wait = 283 (void (*)(GCond *, GMutex *)) g_cond_wait_errorcheck_impl; 284 errorcheck_functions.cond_timed_wait = 285 (gboolean (*)(GCond *, GMutex *, GTimeVal *)) 286 g_cond_timed_wait_errorcheck_impl; 287 288 g_thread_init (&errorcheck_functions); 289 } 290 291 void 292 g_thread_init (GThreadFunctions* init) 293 { 294 gboolean supported; 295 296 if (thread_system_already_initialized) 297 g_error ("GThread system may only be initialized once."); 298 299 thread_system_already_initialized = TRUE; 300 301 if (init == NULL) 302 { 303 #ifdef HAVE_G_THREAD_IMPL_INIT 304 /* now do any initialization stuff required by the 305 * implementation, but only if called with a NULL argument, of 306 * course. Otherwise it's up to the user to do so. */ 307 g_thread_impl_init(); 308 #endif /* HAVE_G_THREAD_IMPL_INIT */ 309 init = &g_thread_functions_for_glib_use_default; 310 } 311 else 312 g_thread_use_default_impl = FALSE; 313 314 g_thread_functions_for_glib_use = *init; 315 if (g_thread_gettime_impl) 316 g_thread_gettime = g_thread_gettime_impl; 317 318 supported = (init->mutex_new && 319 init->mutex_lock && 320 init->mutex_trylock && 321 init->mutex_unlock && 322 init->mutex_free && 323 init->cond_new && 324 init->cond_signal && 325 init->cond_broadcast && 326 init->cond_wait && 327 init->cond_timed_wait && 328 init->cond_free && 329 init->private_new && 330 init->private_get && 331 init->private_set && 332 init->thread_create && 333 init->thread_yield && 334 init->thread_join && 335 init->thread_exit && 336 init->thread_set_priority && 337 init->thread_self); 338 339 /* if somebody is calling g_thread_init (), it means that he wants to 340 * have thread support, so check this 341 */ 342 if (!supported) 343 { 344 if (g_thread_use_default_impl) 345 g_error ("Threads are not supported on this platform."); 346 else 347 g_error ("The supplied thread function vector is invalid."); 348 } 349 350 g_thread_priority_map [G_THREAD_PRIORITY_LOW] = PRIORITY_LOW_VALUE; 351 g_thread_priority_map [G_THREAD_PRIORITY_NORMAL] = PRIORITY_NORMAL_VALUE; 352 g_thread_priority_map [G_THREAD_PRIORITY_HIGH] = PRIORITY_HIGH_VALUE; 353 g_thread_priority_map [G_THREAD_PRIORITY_URGENT] = PRIORITY_URGENT_VALUE; 354 355 g_thread_init_glib (); 356 } 357 358 #else /* !G_THREADS_ENABLED */ 359 360 void 361 g_thread_init (GThreadFunctions* init) 362 { 363 g_error ("GLib thread support is disabled."); 364 } 365 366 void 367 g_thread_init_with_errorcheck_mutexes (GThreadFunctions* init) 368 { 369 g_error ("GLib thread support is disabled."); 370 } 371 372 #endif /* !G_THREADS_ENABLED */ 373