Changes to the mutex code.



Hi everyone,

I'm going to commit a change to the thread system, as currently in GLib. It
includes recursive mutexes. On Linux the native implementation will be used,
thus there is no speed penalty. On other systems, there is however a small
penalty even for normal mutexes (it's one comparision and a function call more
than hitherto, which I think is acceptable). 

In order not to break the API, there still is the function g_mutex_new(), but
now we also got g_mutex_new_recursive. Also there are two initializers
G_STATIC_MUTEX_INIT and G_STATIC_MUTEX_INIT_RECURSIVE. Now GMutex and
GStaticMutex can both be normal and recursive. We could later use that to plug
a recursive mutex into gdk_threads_mutex, thus making life a tad easier for
certain application programmers. 

If you don't like that, I'm cool with that and won't commit it. I'm myself not
100% sure I like it that way, but speed sensitive things can not always be
made the way one likes. 

I'll wait a week and if no objections come in, I'll commit it.

Bye,
Sebastian
-- 
Sebastian Wilhelmi                   |            här ovanför alla molnen
mailto:wilhelmi@ira.uka.de           |     är himmlen så förunderligt blå
http://goethe.ira.uka.de/~wilhelmi   |
Index: acconfig.h
===================================================================
RCS file: /cvs/gnome/glib/acconfig.h,v
retrieving revision 1.24
diff -u -b -B -r1.24 acconfig.h
--- acconfig.h	1999/11/16 10:30:25	1.24
+++ acconfig.h	2000/03/14 15:44:37
@@ -59,8 +59,10 @@
 #undef HAVE_GETPWUID_R_POSIX
 #undef HAVE_LIMITS_H
 #undef HAVE_LONG_DOUBLE
+#undef HAVE_NATIVE_RECURSIVE_MUTEX
 #undef HAVE_POLL
 #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
 #undef HAVE_PWD_H
 #undef HAVE_PW_GECOS
 #undef HAVE_SYS_PARAM_H
Index: configure.in
===================================================================
RCS file: /cvs/gnome/glib/configure.in,v
retrieving revision 1.123
diff -u -b -B -r1.123 configure.in
--- configure.in	2000/03/06 09:09:57	1.123
+++ configure.in	2000/03/14 15:44:37
@@ -668,6 +668,16 @@
 FUNC_NO_LOCALTIME_R="the 'g_date_set_time' function will not be MT-safe
 		because there is no 'localtime_r' on your system."
 
+POSIX_NO_YIELD="I can not find a yield functions for your platform. A rather
+		crude surrogate will be used. If you happen to know a 
+		yield function for your system, please inform the GLib 
+		developers."
+
+POSIX_NO_PRIORITIES="I can not find the minimal and maximal priorities for 
+		threads on your system. Threads can only have the default 
+		priority on your system now. If you happen to know these
+		priorities, please inform the GLib developers."
+
 dnl determination of thread implementation
 dnl ***************************************
 
@@ -682,8 +692,9 @@
 if test "x$want_threads" = xyes || test "x$want_threads" = xposix \
 				|| test "x$want_threads" = xdce; then
 	# -D_POSIX4A_DRAFT10_SOURCE is for DG/UX
-	# -U_OSF_SOURCE if for Digital UNIX 4.0d
-	GTHREAD_COMPILE_IMPL_DEFINES="-D_POSIX4A_DRAFT10_SOURCE -U_OSF_SOURCE"
+	# -U_OSF_SOURCE is for Digital UNIX 4.0d
+	# -D_GNU_SOURCE is for Linux
+	GTHREAD_COMPILE_IMPL_DEFINES="-D_POSIX4A_DRAFT10_SOURCE -U_OSF_SOURCE -D_GNU_SOURCE"
 	glib_save_CPPFLAGS="$CPPFLAGS"
 	CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
         if test "x$have_threads" = xnone; then
@@ -717,6 +728,7 @@
 G_THREAD_CFLAGS=
 
 mutex_has_default=no
+mutex_has_recursive_default=no
 case $have_threads in
         posix|dce)
 		G_THREAD_LIBS=error
@@ -731,12 +743,22 @@
 				add_thread_lib="-l$thread_lib"
 				IN=" in -l$thread_lib"
 			fi
+			if test x"$have_threads" = xposix; then
+				defattr=NULL
+			else
+				defattr=pthread_attr_default
+			fi
 			
 			LIBS="$glib_save_LIBS $add_thread_lib"
 			
-			AC_MSG_CHECKING(for pthread_join$IN)
-			AC_TRY_LINK([#include <pthread.h>],
-				[pthread_t t; pthread_join(t,NULL)],
+			AC_MSG_CHECKING(for pthread_create$IN)
+			AC_TRY_RUN([#include <pthread.h> 
+				void* func(void* data) {}
+                                main()
+				{ pthread_t t; 
+				  exit(pthread_create (&t, $defattr, func, 
+						NULL));
+				}],
 				[AC_MSG_RESULT(yes)
 				G_THREAD_LIBS="$add_thread_lib"
 				break],
@@ -874,6 +896,8 @@
 	fi
 	LIBS="$LIBS $G_THREAD_LIBS"
 	if test x"$have_threads" = xposix; then
+		glib_save_CPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
 		GLIB_SIZEOF([#include <pthread.h>],
 			pthread_t,
 			system_thread)
@@ -917,13 +941,13 @@
 		if test x"$posix_priority_min" = xnone; then
 			AC_MSG_RESULT(none found)
 			AC_MSG_WARN($POSIX_NO_PRIORITIES)
-	                posix_priority_min=1
-			posix_priority_max=1
+	                posix_priority_min=-1
+			posix_priority_max=-1
 		else
 			AC_MSG_RESULT($posix_priority_min/$posix_priority_max)
-		fi
 		AC_DEFINE_UNQUOTED(POSIX_MIN_PRIORITY,$posix_priority_min)
 		AC_DEFINE_UNQUOTED(POSIX_MAX_PRIORITY,$posix_priority_max)
+		fi
 		posix_yield_func=none
 		AC_MSG_CHECKING(for posix yield function)
 		for yield_func in pthread_yield_np pthread_yield sched_yield \
@@ -942,9 +966,11 @@
 			posix_yield_func="$posix_yield_func()"
 		fi
 		AC_DEFINE_UNQUOTED(POSIX_YIELD_FUNC,$posix_yield_func)
+		CPPFLAGS="$glib_save_CPPFLAGS"
 	else
 		# for now, the only other implementation is solaris 
 		# -> there 4 bytes are enough
+		glib_cv_sizeof_system_thread=4
           	AC_DEFINE_UNQUOTED(GLIB_SIZEOF_SYSTEM_THREAD, 4)
 	fi
 
@@ -974,6 +1000,10 @@
 dnl if mutex_has_default = yes, we also got
 dnl mutex_default_type, mutex_default_init and mutex_header_file
 GLIB_IF_VAR_EQ(mutex_has_default, yes,
+	glib_save_CPPFLAGS="$CPPFLAGS"
+	glib_save_LIBS="$LIBS"
+	LIBS="$LIBS $G_THREAD_LIBS"
+	CPPFLAGS="$CPPFLAGS $GTHREAD_COMPILE_IMPL_DEFINES"
 	GLIB_SIZEOF([#include <$mutex_header_file>],
                     $mutex_default_type,
                     gmutex,
@@ -987,13 +1017,21 @@
 		mutex_has_default=no
 	fi
 	if test x"$have_threads" = xposix; then 
-		GLIB_BYTE_CONTENTS([#define __USE_GNU
-#include <$mutex_header_file>],
+                GLIB_BYTE_CONTENTS([#include <$mutex_header_file>],
 				   $mutex_default_type,
 				   grecmutex,
 				   $glib_cv_sizeof_gmutex,
 				   PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
 	fi
+ 	if test x"$glib_cv_byte_contents_grecmutex" != xno -a	\
+	  	x"$glib_cv_byte_contents_grecmutex" != x; then
+		mutex_has_recursive_default=yes
+	fi
+	if test x$mutex_has_recursive_default = xyes; then
+		AC_DEFINE(HAVE_NATIVE_RECURSIVE_MUTEX)
+	fi	
+	CPPFLAGS="$glib_save_CPPFLAGS"
+	LIBS="$glib_save_LIBS"
 	,
 )
 
@@ -1152,62 +1190,68 @@
 #else	/* !__cplusplus */
 $glib_inline
 #endif	/* !__cplusplus */
-_______EOF
 
-	echo >>$outfile
-	if test x$g_mutex_has_default = xyes; then
-		cat >>$outfile <<_______EOF
 $g_enable_threads_def G_THREADS_ENABLED
 #define G_THREADS_IMPL_$g_threads_impl_def
 typedef struct _GStaticMutex GStaticMutex;
-struct _GStaticMutex
+typedef struct _GMutex GMutex;
+_______EOF
+
+	if test x$g_mutex_has_default = xyes; then
+		cat >>$outfile <<_______EOF
+struct _GMutex
 {
-  struct _GMutex *runtime_mutex;
+  /* This _must_ be the first member */
   union {
     char   pad[$g_mutex_sizeof];
     double dummy_double;
     void  *dummy_pointer;
     long   dummy_long;
-  } aligned_pad_u;
-};
-#define	G_STATIC_MUTEX_INIT	{ NULL, { { $g_mutex_contents} } }
-#define	g_static_mutex_get_mutex(mutex) \
-  (g_thread_use_default_impl ? ((GMutex*) &((mutex)->aligned_pad_u)) : \
-   g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex)))
+  } mutex;
+  int recursive;
 _______EOF
-	else
+
+		if test x$g_mutex_has_recursive_default = xyes; then
 		cat >>$outfile <<_______EOF
-$g_enable_threads_def G_THREADS_ENABLED
-#define G_THREADS_IMPL_$g_threads_impl_def
-typedef struct _GMutex* GStaticMutex;
-#define G_STATIC_MUTEX_INIT NULL
-#define g_static_mutex_get_mutex(mutex) (g_static_mutex_get_mutex_impl (mutex))
+};
+#define	G_STATIC_MUTEX_INIT	{ NULL, { { { $g_mutex_contents} }, 0 } } 
+#define	G_STATIC_MUTEX_RECURSIVE_INIT { NULL, { { { $g_recmutex_contents} }, 1 } } 
 _______EOF
-	fi
-	if test x$g_recmutex_contents != xno -a \
-	        x$g_recmutex_contents != x; then
-		# the definition of GStaticRecMutex is not done via 
-		# typedef GStaticMutex GStaticRecMutex to avoid silent
-		# compilation, when a GStaticRecMutex is used where a
-		# GStaticMutex should have been used and vice versa,
-		# because that might fail on other platforms.
+		else
 		cat >>$outfile <<_______EOF
-typedef struct _GStaticRecMutex GStaticRecMutex;
-struct _GStaticRecMutex
-{
-  struct _GMutex *runtime_mutex;
+  int counter;
   union {
-    char   pad[$g_mutex_sizeof];
+    char   pad[$g_thread_sizeof];
     double dummy_double;
     void  *dummy_pointer;
     long   dummy_long;
-  } aligned_pad_u;
+  } thread;
 };
-#define G_STATIC_REC_MUTEX_INIT { NULL, { { $g_recmutex_contents} } }
-#define  g_static_rec_mutex_lock(mutex) g_static_mutex_lock (mutex)
-#define  g_static_rec_mutex_trylock(mutex) g_static_mutex_trylock (mutex)
-#define  g_static_rec_mutex_unlock(mutex) g_static_mutex_unlock (mutex)
-#define  g_static_rec_mutex_get_mutex(mutex) (mutex)
+#define	G_STATIC_MUTEX_INIT	{ NULL, { { { $g_mutex_contents} }, 0, 0, { { 0 } } } }
+#define	G_STATIC_MUTEX_RECURSIVE_INIT	{ NULL, { { { $g_mutex_contents} }, 1, 0, { { 0 } } } }
+_______EOF
+		fi
+		cat >>$outfile <<_______EOF
+struct _GStaticMutex
+{
+  GMutex *runtime_mutex;
+  GMutex static_mutex;
+};
+#define	g_static_mutex_get_mutex(mutex) \
+  (g_thread_use_default_impl ? ((GMutex*) &((mutex)->static_mutex)) : \
+   g_static_mutex_get_mutex_impl (&((mutex)->runtime_mutex), (mutex)->static_mutex.recursive))
+_______EOF
+	else
+		cat >>$outfile <<_______EOF
+struct _GStaticMutex
+{
+  GMutex *runtime_mutex;
+  int recursive;
+};
+#define G_STATIC_MUTEX_INIT { NULL, 0 }
+#define G_STATIC_MUTEX_RECURSIVE_INIT { NULL, 1}
+
+#define g_static_mutex_get_mutex(mutex) (g_static_mutex_get_mutex_impl (&(mutex)->runtime_mutex, (mutex)->recursive))
 _______EOF
 	fi
 
@@ -1455,7 +1499,9 @@
 g_threads_impl_def=$g_threads_impl
 
 g_mutex_has_default="$mutex_has_default"
+g_mutex_has_recursive_default="$mutex_has_recursive_default"
 g_mutex_sizeof="$glib_cv_sizeof_gmutex"
+g_thread_sizeof="$glib_cv_sizeof_system_thread"
 g_mutex_contents="$glib_cv_byte_contents_gmutex"
 g_recmutex_contents="$glib_cv_byte_contents_grecmutex"
 
Index: glib.h
===================================================================
RCS file: /cvs/gnome/glib/glib.h,v
retrieving revision 1.156
diff -u -b -B -r1.156 glib.h
--- glib.h	1997/01/01 04:23:36	1.156
+++ glib.h	2000/03/14 15:44:38
@@ -2935,7 +2935,6 @@
   gboolean joinable;
 };
 
-typedef struct _GMutex		GMutex;
 typedef struct _GCond		GCond;
 typedef struct _GPrivate	GPrivate;
 typedef struct _GStaticPrivate	GStaticPrivate;
@@ -2943,7 +2942,7 @@
 typedef struct _GThreadFunctions GThreadFunctions;
 struct _GThreadFunctions
 {
-  GMutex*  (*mutex_new)           (void);
+  GMutex*   (*mutex_new)          (gboolean              recursive);
   void     (*mutex_lock)          (GMutex		*mutex);
   gboolean (*mutex_trylock)       (GMutex		*mutex);
   void     (*mutex_unlock)        (GMutex		*mutex);
@@ -2987,7 +2986,7 @@
 void	g_thread_init	(GThreadFunctions	*vtable);
 
 /* internal function for fallback static mutex implementation */
-GMutex*	g_static_mutex_get_mutex_impl	(GMutex	**mutex);
+GMutex*	g_static_mutex_get_mutex_impl	(GMutex	**mutex, gboolean recursive);
 
 /* shorthands for conditional and unconditional function calls */
 #define G_THREAD_UF(name, arglist) \
@@ -2998,7 +2997,8 @@
  * recursive in general, don't rely on that
  */
 #define	g_thread_supported()	(g_threads_got_initialized)
-#define g_mutex_new()            G_THREAD_UF (mutex_new,      ())
+#define g_mutex_new()            G_THREAD_UF (mutex_new,      (FALSE))
+#define g_mutex_new_recursive()  G_THREAD_UF (mutex_new,      (TRUE))
 #define g_mutex_lock(mutex)      G_THREAD_CF (mutex_lock,     (void)0, (mutex))
 #define g_mutex_trylock(mutex)   G_THREAD_CF (mutex_trylock,  TRUE,    (mutex))
 #define g_mutex_unlock(mutex)    G_THREAD_CF (mutex_unlock,   (void)0, (mutex))
@@ -3062,24 +3062,6 @@
 				      GThread        *thread,
 				      gpointer        data,
 				      GDestroyNotify  notify);
-#ifndef G_STATIC_REC_MUTEX_INIT
-/* if GStaticRecMutex is not just a differently initialized GStaticMutex, 
- * the following is done:
- * This can't be done in glibconfig.h, as GStaticPrivate and gboolean
- * are not yet known there 
- */
-typedef struct _GStaticRecMutex GStaticRecMutex;
-struct _GStaticRecMutex
-{
-  GStaticMutex mutex;
-  GStaticPrivate counter; 
-};
-#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT, G_STATIC_PRIVATE_INIT }
-void     g_static_rec_mutex_lock    (GStaticRecMutex* mutex);
-gboolean g_static_rec_mutex_trylock (GStaticRecMutex* mutex);
-void     g_static_rec_mutex_unlock  (GStaticRecMutex* mutex);
-#define  g_static_rec_mutex_get_mutex(mutex) ((mutex)->mutex)
-#endif /* G_STATIC_REC_MUTEX_INIT */
 
 typedef struct _GStaticRWLock GStaticRWLock;
 struct _GStaticRWLock
Index: gthread.c
===================================================================
RCS file: /cvs/gnome/glib/gthread.c,v
retrieving revision 1.4
diff -u -b -B -r1.4 gthread.c
--- gthread.c	1999/11/16 10:30:25	1.4
+++ gthread.c	2000/03/14 15:44:38
@@ -45,6 +45,11 @@
  * alien implementaion, as loaded by g_thread_init can only count on
  * "sizeof (gpointer)" bytes to store their info. We however need more
  * for some of our native implementations. */
+
+#ifndef GLIB_SIZEOF_SYSTEM_THREAD
+#define GLIB_SIZEOF_SYSTEM_THREAD SIZEOF_VOID_P
+#endif
+
 union _SystemThread
 {
   guchar   data[GLIB_SIZEOF_SYSTEM_THREAD];
@@ -170,7 +175,7 @@
 }
 
 GMutex *
-g_static_mutex_get_mutex_impl (GMutex** mutex)
+g_static_mutex_get_mutex_impl (GMutex** mutex, gboolean recursive)
 {
   if (!g_thread_supported ())
     return NULL;
@@ -180,54 +185,12 @@
   g_mutex_lock (g_mutex_protect_static_mutex_allocation);
 
   if (!(*mutex)) 
-    *mutex = g_mutex_new(); 
+    *mutex = g_thread_functions_for_glib_use.mutex_new(recursive); 
 
   g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
   
   return *mutex;
 }
-
-#ifndef g_static_rec_mutex_lock
-/* That means, that g_static_rec_mutex_lock is not defined to be 
- * g_static_mutex_lock, we have to provide an implementation ourselves.
- */
-void
-g_static_rec_mutex_lock (GStaticRecMutex* mutex)
-{
-  guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
-  if (counter == 0)
-    {
-      g_static_mutex_lock (&mutex->mutex);
-    }
-  counter++;
-  g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
-}
-
-gboolean
-g_static_rec_mutex_trylock (GStaticRecMutex* mutex)
-{
-  guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
-  if (counter == 0)
-    {
-      if (!g_static_mutex_trylock (&mutex->mutex)) return FALSE;
-    }
-  counter++;
-  g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
-  return TRUE;
-}
-
-void
-g_static_rec_mutex_unlock (GStaticRecMutex* mutex)
-{
-  guint counter = GPOINTER_TO_UINT (g_static_private_get (&mutex->counter));
-  if (counter == 1)
-    {
-      g_static_mutex_unlock (&mutex->mutex);
-    }
-  counter--;
-  g_static_private_set (&mutex->counter, GUINT_TO_POINTER (counter), NULL);
-}
-#endif /* g_static_rec_mutex_lock */
 
 gpointer
 g_static_private_get (GStaticPrivate *private_key)
Index: gthread/gthread-posix.c
===================================================================
RCS file: /cvs/gnome/glib/gthread/gthread-posix.c,v
retrieving revision 1.14
diff -u -b -B -r1.14 gthread-posix.c
--- gthread/gthread-posix.c	2000/02/22 13:11:24	1.14
+++ gthread/gthread-posix.c	2000/03/14 15:44:38
@@ -48,7 +48,7 @@
 
 #if defined(G_THREADS_IMPL_POSIX)
 # define posix_check_for_error( what ) G_STMT_START{             \
-    int error = (what);                                           \
+    gint error = (what);                                           \
     if( error ) { posix_print_error( what, error ); }             \
     }G_STMT_END
 # define mutexattr_default NULL
@@ -67,59 +67,136 @@
 # error This should not happen. Contact the GLib team.
 #endif
 
+#if defined(POSIX_MIN_PRIORITY) && defined(POSIX_MAX_PRIORITY)
+#  define HAVE_PRIORITIES 1
+#endif
+
 gulong g_thread_min_stack_size = 0;
 
+static GStaticMutex init_mutex           = G_STATIC_MUTEX_INIT;
+static GStaticMutex init_mutex_recursive = G_STATIC_MUTEX_RECURSIVE_INIT;
+
 #define HAVE_G_THREAD_IMPL_INIT
 static void 
 g_thread_impl_init()
 {
+#ifdef HAVE_PRIORITIES
   g_thread_min_priority = POSIX_MIN_PRIORITY;
   g_thread_max_priority = POSIX_MAX_PRIORITY;
+#endif
+
 #ifdef _SC_THREAD_STACK_MIN
   g_thread_min_stack_size = MAX (sysconf (_SC_THREAD_STACK_MIN), 0);
 #endif /* _SC_THREAD_STACK_MIN */
 }
 
 static GMutex *
-g_mutex_new_posix_impl (void)
+g_mutex_new_posix_impl (gboolean recursive)
 {
-  GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
-  posix_check_for_error (pthread_mutex_init ((pthread_mutex_t *) result, 
-					     mutexattr_default));
+  GMutex *result = g_new (GMutex, 1);
+
+  if (recursive)
+    *result = init_mutex_recursive.static_mutex;
+  else
+    *result = init_mutex.static_mutex;     
+  
   return result;
 }
 
 static void
 g_mutex_free_posix_impl (GMutex * mutex)
 {
-  posix_check_for_error (pthread_mutex_destroy ((pthread_mutex_t *) mutex));
   g_free (mutex);
 }
 
 /* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
-   functions from gmem.c and gmessages.c; */
+ * functions from gmem.c and gmessages.c. */
 
-/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly, as
-   signature and semantic are right, but without error check then!!!!,
-   we might want to change this therefore. */
+/* pthread_mutex_lock, pthread_mutex_unlock can be taken directly for
+ * platforms with native recursive locks, as signature and semantic
+ * are right, but without error check then! */
+
+#ifdef HAVE_NATIVE_RECURSIVE_MUTEX
+#define g_mutex_lock_posix_impl   ((void (*)(GMutex *)) pthread_mutex_lock)
+#define g_mutex_unlock_posix_impl ((void (*)(GMutex *)) pthread_mutex_unlock)
+#else /* !HAVE_NATIVE_RECURSIVE_MUTEX */
 
-static gboolean
-g_mutex_trylock_posix_impl (GMutex * mutex)
+# define MUTEX_THREAD(mutex) (*((pthread_t*)&mutex->thread))
+static pthread_t zero_thread;
+
+static void
+g_mutex_lock_posix_impl (GMutex * mutex)
 {
-  int result;
+  if (mutex->recursive)
+    {
+      pthread_t self = pthread_self ();
+      if (pthread_equal (self, MUTEX_THREAD(mutex)))
+	{
+	  mutex->counter++;
+	  return;
+	}
+      pthread_mutex_lock ((pthread_mutex_t*) mutex);
+      MUTEX_THREAD(mutex) = self;
+      mutex->counter = 0;
+    }
+  else
+    pthread_mutex_lock ((pthread_mutex_t*) mutex);
+}
 
-  result = pthread_mutex_trylock ((pthread_mutex_t *) mutex);
+static void
+g_mutex_unlock_posix_impl (GMutex * mutex)
+{
+  if (mutex->recursive)
+    {
+      if (mutex->counter > 0)
+	{
+	  mutex->counter--;
+	  return;
+	}
+      MUTEX_THREAD (mutex) = zero_thread;
+    }
+  pthread_mutex_unlock ((pthread_mutex_t*) mutex);
+}
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */
 
 #ifdef G_THREADS_IMPL_POSIX
-  if (result == EBUSY)
-    return FALSE;
+#define EVAL_MUTEX_TRYLOCK_RESULT(result)				\
+  if (result == EBUSY) return FALSE; else posix_check_for_error(result); 
 #else /* G_THREADS_IMPL_DCE */
-  if (result == 0)
-    return FALSE;
+#define EVAL_MUTEX_TRYLOCK_RESULT(result)				\
+  if (result == 0) return FALSE; else posix_check_for_error(result); 
 #endif
 
-  posix_check_for_error (result);
+static gboolean
+g_mutex_trylock_posix_impl (GMutex * mutex)
+{
+  g_return_val_if_fail (mutex != NULL, FALSE);
+
+#ifndef HAVE_NATIVE_RECURSIVE_MUTEX 
+  if (mutex->recursive)
+    {
+      pthread_t self = pthread_self ();
+      gint result;
+      if (pthread_equal (self, MUTEX_THREAD (mutex)))
+	{
+	  mutex->counter++;
+	  return TRUE;
+	}
+      result = pthread_mutex_trylock ((pthread_mutex_t*) mutex);
+      EVAL_MUTEX_TRYLOCK_RESULT (result);
+
+      MUTEX_THREAD (mutex) = self;
+      mutex->counter = 0;
   return TRUE;
+    }
+  else
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */
+    {
+      gint result = pthread_mutex_trylock ((pthread_mutex_t*) mutex);
+      EVAL_MUTEX_TRYLOCK_RESULT (result);
+      
+      return TRUE;
+    }
 }
 
 static GCond *
@@ -132,9 +209,9 @@
 }
 
 /* pthread_cond_signal, pthread_cond_broadcast and pthread_cond_wait
-   can be taken directly, as signature and semantic are right, but
-   without error check then!!!!, we might want to change this
-   therfore. */
+ * (the last one only for platforms with native recursive locks) can
+ * be taken directly, as signature and semantic are right, but without
+ * error check then! */
 
 #define G_MICROSEC 1000000
 #define G_NANOSEC 1000000000
@@ -147,6 +224,9 @@
   int result;
   struct timespec end_time;
   gboolean timed_out;
+#ifndef HAVE_NATIVE_RECURSIVE_MUTEX
+  gint old_count = 0;
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */  
 
   g_return_val_if_fail (cond != NULL, FALSE);
   g_return_val_if_fail (entered_mutex != NULL, FALSE);
@@ -157,6 +237,14 @@
       return TRUE;
     }
 
+#ifndef HAVE_NATIVE_RECURSIVE_MUTEX
+  if (entered_mutex->recursive)
+    {
+      old_count = entered_mutex->counter;
+      MUTEX_THREAD (entered_mutex) = zero_thread;
+    }
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */  
+
   end_time.tv_sec = abs_time->tv_sec;
   end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
   g_assert (end_time.tv_nsec < G_NANOSEC);
@@ -160,10 +248,20 @@
   end_time.tv_sec = abs_time->tv_sec;
   end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
   g_assert (end_time.tv_nsec < G_NANOSEC);
+
+
   result = pthread_cond_timedwait ((pthread_cond_t *) cond,
-				   (pthread_mutex_t *) entered_mutex,
+				   (pthread_mutex_t*) entered_mutex,
 				   &end_time);
 
+#ifndef HAVE_NATIVE_RECURSIVE_MUTEX
+  if (entered_mutex->recursive)
+    {
+      entered_mutex->counter = old_count;
+      MUTEX_THREAD (entered_mutex) = pthread_self();
+    }
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */  
+
 #ifdef G_THREADS_IMPL_POSIX
   timed_out = (result == ETIMEDOUT);
 #else /* G_THREADS_IMPL_DCE */
@@ -175,6 +273,36 @@
   return !timed_out;
 }
 
+#ifdef HAVE_NATIVE_RECURSIVE_MUTEX
+#define g_cond_wait_posix_impl ((void (*)(GCond*, GMutex*)) pthread_cond_wait)
+#else /* !HAVE_NATIVE_RECURSIVE_MUTEX */
+static void
+g_cond_wait_posix_impl (GCond * cond,
+			GMutex * entered_mutex)
+{
+  gint old_count = 0;
+
+  g_return_if_fail (cond != NULL);
+  g_return_if_fail (entered_mutex != NULL);
+
+  if (entered_mutex->recursive)
+    {
+      old_count = entered_mutex->counter;
+      MUTEX_THREAD (entered_mutex) = zero_thread;
+    }
+  
+  posix_check_for_error 
+    (pthread_cond_wait ((pthread_cond_t *) cond,
+			(pthread_mutex_t *) entered_mutex));
+     
+  if (entered_mutex->recursive)
+    {
+      entered_mutex->counter = old_count;
+      MUTEX_THREAD (entered_mutex) = pthread_self();
+    }
+}
+#endif /* HAVE_NATIVE_RECURSIVE_MUTEX */
+
 static void
 g_cond_free_posix_impl (GCond * cond)
 {
@@ -212,8 +340,7 @@
 #else /* G_THREADS_IMPL_DCE */
   {
     void* data;
-    posix_check_for_error (pthread_getspecific (*(pthread_key_t *) 
-						private_key, &data));
+    pthread_getspecific (*(pthread_key_t *) private_key, &data);
     return data;
   }
 #endif
@@ -244,8 +371,9 @@
 
 #ifdef PTHREAD_SCOPE_SYSTEM
   if (bound)
-     posix_check_for_error (pthread_attr_setscope (&attr, 
-						   PTHREAD_SCOPE_SYSTEM));
+    /* No error check here, because some systems can't do it and we
+     * simply don't want threads to fail because of that. */
+    pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
 #endif /* PTHREAD_SCOPE_SYSTEM */
 
 #ifdef G_THREADS_IMPL_POSIX
@@ -253,17 +381,19 @@
           joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
 #endif /* G_THREADS_IMPL_POSIX */
   
-#ifdef G_THREADS_IMPL_POSIX
+#ifdef HAVE_PRIORITIES
+# ifdef G_THREADS_IMPL_POSIX
   {
     struct sched_param sched;
     posix_check_for_error (pthread_attr_getschedparam (&attr, &sched));
     sched.sched_priority = g_thread_map_priority (priority);
     posix_check_for_error (pthread_attr_setschedparam (&attr, &sched));
   }
-#else /* G_THREADS_IMPL_DCE */
+# else /* G_THREADS_IMPL_DCE */
   posix_check_for_error 
     (pthread_attr_setprio (&attr, g_thread_map_priority (priority)));
-#endif /* G_THREADS_IMPL_DCE */
+# endif /* G_THREADS_IMPL_DCE */
+#endif /* HAVE_PRIORITIES */
 
   posix_check_for_error (pthread_create (thread, &attr, 
                                          (void* (*)(void*))thread_func,
@@ -300,7 +430,8 @@
 static void
 g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
 {
-#ifdef G_THREADS_IMPL_POSIX
+#ifdef HAVE_PRIORITIES
+# ifdef G_THREADS_IMPL_POSIX
   struct sched_param sched;
   int policy;
   posix_check_for_error (pthread_getschedparam (*(pthread_t*)thread, 
@@ -308,10 +439,11 @@
   sched.sched_priority = g_thread_map_priority (priority);
   posix_check_for_error (pthread_setschedparam (*(pthread_t*)thread, 
 						policy, &sched));
-#else /* G_THREADS_IMPL_DCE */
+# else /* G_THREADS_IMPL_DCE */
   posix_check_for_error (pthread_setprio (*(pthread_t*)thread, 
 					  g_thread_map_priority (priority)));
-#endif
+# endif
+#endif /* HAVE_PRIORITIES */
 }
 
 static void
@@ -323,14 +455,14 @@
 static GThreadFunctions g_thread_functions_for_glib_use_default =
 {
   g_mutex_new_posix_impl,
-  (void (*)(GMutex *)) pthread_mutex_lock,
+  g_mutex_lock_posix_impl,
   g_mutex_trylock_posix_impl,
-  (void (*)(GMutex *)) pthread_mutex_unlock,
+  g_mutex_unlock_posix_impl,
   g_mutex_free_posix_impl,
   g_cond_new_posix_impl,
   (void (*)(GCond *)) pthread_cond_signal,
   (void (*)(GCond *)) pthread_cond_broadcast,
-  (void (*)(GCond *, GMutex *)) pthread_cond_wait,
+  g_cond_wait_posix_impl,
   g_cond_timed_wait_posix_impl,
   g_cond_free_posix_impl,
   g_private_new_posix_impl,
Index: gthread/gthread-solaris.c
===================================================================
RCS file: /cvs/gnome/glib/gthread/gthread-solaris.c,v
retrieving revision 1.7
diff -u -b -B -r1.7 gthread-solaris.c
--- gthread/gthread-solaris.c	2000/02/22 13:11:24	1.7
+++ gthread/gthread-solaris.c	2000/03/14 15:44:38
@@ -63,10 +63,11 @@
 }
 
 static GMutex *
-g_mutex_new_solaris_impl (void)
+g_mutex_new_solaris_impl (gboolean recursive)
 {
-  GMutex *result = (GMutex *) g_new (mutex_t, 1);
+  GMutex *result = g_new (GMutex, 1);
   solaris_check_for_error (mutex_init ((mutex_t *) result, USYNC_PROCESS, 0));
+  result->recursive = recursive;
   return result;
 }
 
@@ -80,19 +81,72 @@
 /* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
    functions from gmem.c and gmessages.c; */
 
-/* mutex_lock, mutex_unlock can be taken directly, as
-   signature and semantic are right, but without error check then!!!!,
-   we might want to change this therefore. */
+# define MUTEX_THREAD(mutex) (*((thread_t*)&mutex->thread))
+static thread_t zero_thread;
 
+static void
+g_mutex_lock_solaris_impl (GMutex * mutex)
+{
+  if (mutex->recursive)
+    {
+      thread_t self = thr_self ();
+      if (self == MUTEX_THREAD(mutex))
+	{
+	  mutex->counter++;
+	  return;
+	}
+      mutex_lock ((mutex_t*) mutex);
+      MUTEX_THREAD(mutex) = self;
+      mutex->counter = 0;
+    }
+  else
+    mutex_lock ((mutex_t*) mutex);
+}
+
+static void
+g_mutex_unlock_solaris_impl (GMutex * mutex)
+{
+  if (mutex->recursive)
+    {
+      if (mutex->counter > 0)
+	{
+	  mutex->counter--;
+	  return;
+	}
+      MUTEX_THREAD (mutex) = zero_thread;
+    }
+  mutex_unlock ((mutex_t*) mutex);
+}
+
 static gboolean
 g_mutex_trylock_solaris_impl (GMutex * mutex)
 {
-  int result;
+  gint result;
+  if (mutex->recursive)
+    {
+      thread_t self = thr_self ();
+      if (self == MUTEX_THREAD (mutex))
+        {
+          mutex->counter++;
+          return TRUE;
+        }
+      result = mutex_trylock ((mutex_t*) mutex);
+      if (result == EBUSY)
+	return FALSE;
+      solaris_check_for_error (result);
+
+      MUTEX_THREAD (mutex) = self;
+      mutex->counter = 0;
+      return TRUE;
+    }
+  else
+    {
   result = mutex_trylock ((mutex_t *) mutex);
   if (result == EBUSY)
     return FALSE;
   solaris_check_for_error (result);
   return TRUE;
+    }
 }
 
 static GCond *
@@ -103,10 +157,8 @@
   return result;
 }
 
-/* cond_signal, cond_broadcast and cond_wait
-   can be taken directly, as signature and semantic are right, but
-   without error check then!!!!, we might want to change this
-   therfore. */
+/* cond_signal and cond_broadcast can be taken directly, as signature
+   and semantic are right, but without error check then! */
 
 #define G_MICROSEC 1000000
 #define G_NANOSEC 1000000000
@@ -119,6 +171,7 @@
   int result;
   timestruc_t end_time;
   gboolean timed_out;
+  gint old_count = 0;
 
   g_return_val_if_fail (cond != NULL, FALSE);
   g_return_val_if_fail (entered_mutex != NULL, FALSE);
@@ -129,11 +182,24 @@
       return TRUE;
     }
 
+  if (entered_mutex->recursive)
+    {
+      old_count = entered_mutex->counter;
+      MUTEX_THREAD (entered_mutex) = zero_thread;
+    }
+
   end_time.tv_sec = abs_time->tv_sec;
   end_time.tv_nsec = abs_time->tv_usec * (G_NANOSEC / G_MICROSEC);
   g_assert (end_time.tv_nsec < G_NANOSEC);
   result = cond_timedwait ((cond_t *) cond, (mutex_t *) entered_mutex,
 			   &end_time);
+
+  if (entered_mutex->recursive)
+    {
+      entered_mutex->counter = old_count;
+      MUTEX_THREAD (entered_mutex) = thr_self();
+    }
+
   timed_out = (result == ETIME);
   if (!timed_out)
     solaris_check_for_error (result);
@@ -141,6 +207,31 @@
 }
 
 static void
+g_cond_wait_solaris_impl (GCond * cond,
+			GMutex * entered_mutex)
+{
+  gint old_count = 0;
+
+  g_return_if_fail (cond != NULL);
+  g_return_if_fail (entered_mutex != NULL);
+
+  if (entered_mutex->recursive)
+    {
+      old_count = entered_mutex->counter;
+      MUTEX_THREAD (entered_mutex) = zero_thread;
+    }
+  
+  solaris_check_for_error (cond_wait ((cond_t *) cond,
+				      (mutex_t *) entered_mutex));
+     
+  if (entered_mutex->recursive)
+    {
+      entered_mutex->counter = old_count;
+      MUTEX_THREAD (entered_mutex) = thr_self();
+    }
+}
+
+static void
 g_cond_free_solaris_impl (GCond * cond)
 {
   solaris_check_for_error (cond_destroy ((cond_t *) cond));
@@ -238,14 +329,14 @@
 static GThreadFunctions g_thread_functions_for_glib_use_default =
 {
   g_mutex_new_solaris_impl,
-  (void (*)(GMutex *)) mutex_lock,
+  g_mutex_lock_solaris_impl,
   g_mutex_trylock_solaris_impl,
-  (void (*)(GMutex *)) mutex_unlock,
+  g_mutex_unlock_solaris_impl,
   g_mutex_free_solaris_impl,
   g_cond_new_solaris_impl,
   (void (*)(GCond *)) cond_signal,
   (void (*)(GCond *)) cond_broadcast,
-  (void (*)(GCond *, GMutex *)) cond_wait,
+  g_cond_wait_solaris_impl,
   g_cond_timed_wait_solaris_impl,
   g_cond_free_solaris_impl,
   g_private_new_solaris_impl,
Index: tests/thread-test.c
===================================================================
RCS file: /cvs/gnome/glib/tests/thread-test.c,v
retrieving revision 1.1
diff -u -b -B -r1.1 thread-test.c
--- tests/thread-test.c	1999/06/17 15:39:31	1.1
+++ tests/thread-test.c	2000/03/14 15:44:38
@@ -32,22 +32,22 @@
   g_mutex_free (test_g_mutex_mutex);
 }
 
-/* GStaticRecMutex */
+/* GStaticMutex recursive */
 
-static GStaticRecMutex test_g_static_rec_mutex_mutex = G_STATIC_REC_MUTEX_INIT;
+static GStaticMutex test_g_static_rec_mutex_mutex = G_STATIC_MUTEX_RECURSIVE_INIT;
 static guint test_g_static_rec_mutex_int = 0;
 
 static void
 test_g_static_rec_mutex_thread (gpointer data)
 {
   g_assert (GPOINTER_TO_INT (data) == 42);
-  g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex) 
+  g_assert (g_static_mutex_trylock (&test_g_static_rec_mutex_mutex) 
 	    == FALSE);
-  g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
-  g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_lock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_lock (&test_g_static_rec_mutex_mutex);
   g_assert (test_g_static_rec_mutex_int == 42);
-  g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
-  g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_unlock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_unlock (&test_g_static_rec_mutex_mutex);
 }
 
 static void
@@ -55,21 +55,21 @@
 {
   GThread *thread;
 
-  g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex));
+  g_assert (g_static_mutex_trylock (&test_g_static_rec_mutex_mutex));
   thread = g_thread_create (test_g_static_rec_mutex_thread, 
 			    GINT_TO_POINTER (42),
 			    0, TRUE, TRUE, G_THREAD_PRIORITY_NORMAL);
   g_usleep (G_MICROSEC);
-  g_assert (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex));
+  g_assert (g_static_mutex_trylock (&test_g_static_rec_mutex_mutex));
   g_usleep (G_MICROSEC);
   test_g_static_rec_mutex_int = 41;
-  g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_unlock (&test_g_static_rec_mutex_mutex);
   test_g_static_rec_mutex_int = 42;  
-  g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_unlock (&test_g_static_rec_mutex_mutex);
   g_usleep (G_MICROSEC);
-  g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_lock (&test_g_static_rec_mutex_mutex);
   test_g_static_rec_mutex_int = 0;  
-  g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
+  g_static_mutex_unlock (&test_g_static_rec_mutex_mutex);
   g_thread_join (thread);
 }
 
@@ -221,6 +221,15 @@
 }
 
 /* run all the tests */
+void
+run_all_tests()
+{
+  test_g_mutex ();
+  test_g_static_rec_mutex ();
+  test_g_static_private ();
+  test_g_static_rw_lock ();  
+}
+
 int 
 main (int   argc,
       char *argv[])
@@ -229,10 +238,15 @@
      implementation is available */
 #if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE)
   g_thread_init (NULL);
-  test_g_mutex ();
-  test_g_static_rec_mutex ();
-  test_g_static_private ();
-  test_g_static_rw_lock ();
+  run_all_tests ();
+
+  /* Now we rerun all tests, but this time we fool the system into
+   * thinking, that the provided thread system is not native, but
+   * userprovided. */
+
+  g_thread_use_default_impl = FALSE;
+  run_all_tests ();
+  
 #endif
   return 0;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]