Home | History | Annotate | Download | only in gthread
      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