Completed the thread support in GLib. Thread creation, prioritizing
authorSebastian Wilhelmi <wilhelmi@ira.uka.de>
Thu, 17 Jun 1999 15:39:31 +0000 (15:39 +0000)
committerSebastian Wilhelmi <wilhelmi@src.gnome.org>
Thu, 17 Jun 1999 15:39:31 +0000 (15:39 +0000)
1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>

* configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
Completed the thread support in GLib. Thread creation,
prioritizing threads, yielding, joining threads as well as
reader/writer locks and recursive mutexes are now in place. Please
test heavily on your platform. It is so far tested on
Linux/i386/pthreads, Solaris/Sparc/pthreads and
Solaris/Sparc/solaristhreads.

* gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
thread safe sleeping. (sleep() is not MT-safe at all!)

* gutils.c: Avoid compiler warning.

* tests/Makefile.am, tests/thread-test.c: New program to test some
aspects of the thread implementation.

* gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
change of content.

* configure.in: Purged all appearances of nspr.

* gthread/gthread-posix.c, gthread-solaris.c: Added the native
implementations for the GLib's extended thread support.

* gthread/gthread-nspr.c: Removed for good. NSPR is nothing we
would want to build upon.

* gthread/gthread.c: Renamed to gthread-impl.c to avoid
confusion with ../gthread.c (Formerly known as the file called
gmutex.c)

* gthread/testgthread.c: Removed. The new and much extended
        tests are in ../tests/thread-test.c.

* gthread/Makefile.am: Changed to reflect the changes above.

31 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
Makefile.am
acconfig.h
acglib.m4
configure.in
glib.h
glib/Makefile.am
glib/glib.h
glib/gthread.c [new file with mode: 0644]
glib/gtimer.c
glib/gutils.c
gmutex.c [deleted file]
gthread.c [new file with mode: 0644]
gthread/ChangeLog
gthread/Makefile.am
gthread/gthread-impl.c [moved from gthread/gthread.c with 76% similarity]
gthread/gthread-nspr.c [deleted file]
gthread/gthread-posix.c
gthread/gthread-solaris.c
gthread/testgthread.c [deleted file]
gtimer.c
gutils.c
tests/Makefile.am
tests/thread-test.c [new file with mode: 0644]

index 79d4c3d..1883290 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 79d4c3d..1883290 100644 (file)
@@ -1,3 +1,26 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
+       Completed the thread support in GLib. Thread creation,
+       prioritizing threads, yielding, joining threads as well as
+       reader/writer locks and recursive mutexes are now in place. Please
+       test heavily on your platform. It is so far tested on
+       Linux/i386/pthreads, Solaris/Sparc/pthreads and
+       Solaris/Sparc/solaristhreads.
+
+       * gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
+       thread safe sleeping. (sleep() is not MT-safe at all!)
+
+       * gutils.c: Avoid compiler warning.
+
+       * tests/Makefile.am, tests/thread-test.c: New program to test some
+       aspects of the thread implementation.
+
+       * gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
+       change of content.
+
+       * configure.in: Purged all appearances of nspr. 
+
 Wed Jun  2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
 
        * acinclude.m4
index 0725691..f5a8c47 100644 (file)
@@ -40,7 +40,6 @@ libglib_la_SOURCES = \
        gmain.c         \
        gmem.c          \
        gmessages.c     \
-       gmutex.c        \
        gnode.c         \
        gprimes.c       \
        gqueue.c        \
@@ -51,6 +50,7 @@ libglib_la_SOURCES = \
        gstack.c        \
        gstrfuncs.c     \
        gstring.c       \
+       gthread.c       \
        gtimer.c        \
        gtree.c         \
        gutils.c
index aaa035c..1c630e1 100644 (file)
@@ -43,7 +43,9 @@
 #undef G_THREADS_ENABLED
 
 #undef GLIB_SIZEOF_GMUTEX
+#undef GLIB_SIZEOF_PTHREAD_T
 #undef GLIB_BYTE_CONTENTS_GMUTEX
+#undef GLIB_BYTE_CONTENTS_GRECMUTEX
 
 #undef HAVE_BROKEN_WCTYPE
 #undef HAVE_DOPRNT
@@ -53,6 +55,7 @@
 #undef HAVE_LIMITS_H
 #undef HAVE_LONG_DOUBLE
 #undef HAVE_POLL
+#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
 #undef HAVE_PWD_H
 #undef HAVE_PW_GECOS
 #undef HAVE_SYS_PARAM_H
@@ -94,6 +97,9 @@
 #undef NATIVE_WIN32
 
 #undef G_THREAD_SOURCE
+#undef POSIX_MIN_PRIORITY
+#undef POSIX_MAX_PRIORITY
+#undef POSIX_YIELD_FUNC
 
 #undef GLIB_NATIVE_BEOS
 
index 5d3cd93..314d9e4 100644 (file)
--- a/acglib.m4
+++ b/acglib.m4
@@ -58,7 +58,7 @@ define(<<AC_TYPE_NAME>>, translit(glib_byte_contents_$3, [a-z *], [A-Z_P]))dnl
 dnl The cache variable name.
 define(<<AC_CV_NAME>>, translit(glib_cv_byte_contents_$3, [ *], [_p]))dnl
 changequote([, ])dnl
-AC_MSG_CHECKING(byte contents of $2)
+AC_MSG_CHECKING(byte contents of $5)
 AC_CACHE_VAL(AC_CV_NAME,
 [AC_TRY_RUN([#include <stdio.h>
 $1
@@ -73,7 +73,7 @@ main()
     fprintf(f, "%s%d", i?",":"", *(p++));
   fprintf(f, "\n");
   exit(0);
-}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=0, AC_CV_NAME=0)])dnl
+}], AC_CV_NAME=`cat conftestval`, AC_CV_NAME=no, AC_CV_NAME=no)])dnl
 AC_MSG_RESULT($AC_CV_NAME)
 AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME)
 undefine([AC_TYPE_NAME])dnl
index e459f6e..94ba9d5 100644 (file)
@@ -576,7 +576,7 @@ dnl ***********************
 dnl *** g_thread checks ***
 dnl ***********************
 
-AC_ARG_WITH(threads, [  --with-threads=[none/posix/dce/solaris/nspr] specify a thread implementation to use],
+AC_ARG_WITH(threads, [  --with-threads=[none/posix/dce/solaris] specify a thread implementation to use],
        if test "x$with_threads" = x; then
                want_threads=yes
        else
@@ -646,11 +646,6 @@ if test "x$want_threads" = xyes || test "x$want_threads" = xposix \
         fi
        CPPFLAGS="$glib_save_CPPFLAGS"
 fi
-if test "x$want_threads" = xyes || test "x$want_threads" = xnspr; then
-        if test "x$have_threads" = xnone; then
-               AC_CHECK_LIB(nspr21, PRP_NewNakedCondVar, have_threads=nspr)
-       fi
-fi
 
 AC_MSG_CHECKING(for thread implementation)
 
@@ -717,11 +712,6 @@ case $have_threads in
                 mutex_header_file='thread.h'
                g_threads_impl="SOLARIS"
                 ;;
-       nspr)
-               AC_CHECK_LIB(nspr21, PRP_NewNakedCondVar,
-                            G_THREAD_LIBS="-lnspr21")
-               g_threads_impl="NSPR"
-               ;;
         none)
                g_threads_impl="NONE"
                 ;;
@@ -830,6 +820,77 @@ if test x"$enable_threads" = xyes; then
                                AC_DEFINE(HAVE_GETPWUID_R_POSIX)])
                fi
        fi
+       LIBS="$LIBS $G_THREAD_LIBS"
+       if test x"$have_threads" = xposix; then
+               GLIB_SIZEOF([#include <pthread.h>],
+                       pthread_t,
+                       pthread_t)
+               # This is not AC_CHECK_FUNC to also work with function
+               # name mangling in header files.
+               AC_MSG_CHECKING(for pthread_attr_setstacksize)
+               AC_TRY_COMPILE([#include <pthread.h>],
+                       [pthread_attr_setstacksize(NULL,0)],
+                       [AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_PTHREAD_ATTR_SETSTACKSIZE)],
+                       [AC_MSG_RESULT(no)])
+               # If sched_get_priority_min(SCHED_OTHER) returns something 
+               # negative, we ignore it. This happens on Solaris.
+               AC_MSG_CHECKING(for minimal/maximal thread priority)
+               AC_TRY_RUN([#include <pthread.h>
+                    int main () 
+                    { return sched_get_priority_min(SCHED_OTHER) < 0;}],
+                    [posix_priority_min="sched_get_priority_min(SCHED_OTHER)"
+                    posix_priority_max="sched_get_priority_max(SCHED_OTHER)"],
+                    [posix_priority_min=none])
+               if test x"$posix_priority_min" = xnone; then
+                       AC_EGREP_CPP(PX_PRIO_MIN,[#include <pthread.h>
+                               PX_PRIO_MIN],,[
+                               posix_priority_min=PX_PRIO_MIN
+                               posix_priority_max=PX_PRIO_MAX])
+               fi
+               if test x"$posix_priority_min" = xnone; then
+                       AC_EGREP_CPP(PRI_OTHER_MIN,[#include <pthread.h>
+                               PRI_OTHER_MIN],,[
+                               posix_priority_min=PRI_OTHER_MIN        
+                               posix_priority_max=PRI_OTHER_MAX])
+               fi
+               if test x"$posix_priority_min" = xnone; then
+                       case $host in
+                               *-*-solaris*)
+                               posix_priority_min=1
+                               posix_priority_max=127
+                               ;;
+                       esac
+               fi
+               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
+               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)
+               posix_yield_func=none
+               AC_MSG_CHECKING(for posix yield function)
+               for yield_func in pthread_yield_np pthread_yield sched_yield \
+                                                       thr_yield; do
+                       AC_TRY_LINK([#include <pthread.h>],
+                               [$yield_func()],
+                               [posix_yield_func="$yield_func"
+                               break])
+               done            
+               if test x"$posix_yield_func" = xnone; then
+                       AC_MSG_RESULT(none found)
+                       AC_MSG_WARN($POSIX_NO_YIELD)
+                       posix_yield_func="g_thread_sleep(1000)"
+               else
+                       AC_MSG_RESULT($posix_yield_func)
+                       posix_yield_func="$posix_yield_func()"
+               fi
+               AC_DEFINE_UNQUOTED(POSIX_YIELD_FUNC,$posix_yield_func)
+       fi
        LIBS="$glib_save_LIBS"
        CFLAGS="$glib_save_CFLAGS"
 
@@ -865,6 +926,14 @@ GLIB_IF_VAR_EQ(mutex_has_default, yes,
                           gmutex,
                           $glib_cv_sizeof_gmutex,
                           $mutex_default_init)
+       if test x"$have_threads" = xposix; then 
+               GLIB_BYTE_CONTENTS([#define __USE_GNU
+#include <$mutex_header_file>],
+                                  $mutex_default_type,
+                                  grecmutex,
+                                  $glib_cv_sizeof_gmutex,
+                                  PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+       fi
        ,
 )
 
@@ -1054,6 +1123,32 @@ typedef struct _GMutex* GStaticMutex;
 #define g_static_mutex_get_mutex(mutex) (g_static_mutex_get_mutex_impl (mutex))
 _______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 micht fail on other platforms.
+               cat >>$outfile <<_______EOF
+typedef struct _GStaticRecMutex GStaticRecMutex;
+struct _GStaticRecMutex
+{
+  struct _GMutex *runtime_mutex;
+  union {
+    char   pad[$g_mutex_sizeof];
+    double dummy_double;
+    void  *dummy_pointer;
+    long   dummy_long;
+  } aligned_pad_u;
+};
+#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)
+_______EOF
+       fi
 
        echo >>$outfile
        g_bit_sizes="16 32"
@@ -1296,6 +1391,7 @@ g_threads_impl_def=$g_threads_impl
 g_mutex_has_default="$mutex_has_default"
 g_mutex_sizeof="$glib_cv_sizeof_gmutex"
 g_mutex_contents="$glib_cv_byte_contents_gmutex"
+g_recmutex_contents="$glib_cv_byte_contents_grecmutex"
 
 if test "x$glib_native_beos" = "xyes"; then
     glib_native_beos_def="\$glib_native_beos_def
diff --git a/glib.h b/glib.h
index 2587368..0137c82 100644 (file)
--- a/glib.h
+++ b/glib.h
@@ -1500,6 +1500,9 @@ void g_blow_chunks (void);
 
 /* Timer
  */
+
+#define G_MICROSEC 1000000
+
 GTimer* g_timer_new    (void);
 void   g_timer_destroy (GTimer  *timer);
 void   g_timer_start   (GTimer  *timer);
@@ -1507,7 +1510,7 @@ void      g_timer_stop    (GTimer  *timer);
 void   g_timer_reset   (GTimer  *timer);
 gdouble g_timer_elapsed (GTimer         *timer,
                         gulong  *microseconds);
-
+void    g_usleep        (gulong microseconds);
 
 /* String utility functions that modify a string argument or
  * return a constant string that must not be freed.
@@ -2367,7 +2370,6 @@ gsize        g_date_strftime              (gchar       *s,
                                            const gchar *format,
                                            GDate       *date);
 
-
 /* GRelation
  *
  * Indexed Relations.  Imagine a really simple table in a
@@ -2819,31 +2821,63 @@ gint            gwin_closedir   (DIR            *dir);
 
 /* GLib Thread support
  */
+
+typedef void           (*GThreadFunc)          (gpointer       value);
+
+typedef enum
+{
+    G_THREAD_PRIORITY_LOW,
+    G_THREAD_PRIORITY_NORMAL,
+    G_THREAD_PRIORITY_HIGH,
+    G_THREAD_PRIORITY_URGENT, 
+} GThreadPriority;
+
+typedef struct _GThread         GThread;
+struct  _GThread
+{
+  GThreadPriority priority;
+  gboolean bound;
+  gboolean joinable;
+};
+
 typedef struct _GMutex         GMutex;
 typedef struct _GCond          GCond;
 typedef struct _GPrivate       GPrivate;
 typedef struct _GStaticPrivate GStaticPrivate;
+
 typedef struct _GThreadFunctions GThreadFunctions;
 struct _GThreadFunctions
 {
-  GMutex*  (*mutex_new)       (void);
-  void     (*mutex_lock)      (GMutex          *mutex);
-  gboolean (*mutex_trylock)   (GMutex          *mutex);
-  void     (*mutex_unlock)    (GMutex          *mutex);
-  void     (*mutex_free)      (GMutex          *mutex);
-  GCond*   (*cond_new)        (void);
-  void     (*cond_signal)     (GCond           *cond);
-  void     (*cond_broadcast)  (GCond           *cond);
-  void     (*cond_wait)       (GCond           *cond,
-                              GMutex           *mutex);
-  gboolean (*cond_timed_wait) (GCond           *cond,
-                              GMutex           *mutex, 
-                              GTimeVal         *end_time);
-  void      (*cond_free)      (GCond           *cond);
-  GPrivate* (*private_new)    (GDestroyNotify   destructor);
-  gpointer  (*private_get)    (GPrivate                *private_key);
-  void      (*private_set)    (GPrivate                *private_key,
-                              gpointer          data);
+  GMutex*  (*mutex_new)           (void);
+  void     (*mutex_lock)          (GMutex              *mutex);
+  gboolean (*mutex_trylock)       (GMutex              *mutex);
+  void     (*mutex_unlock)        (GMutex              *mutex);
+  void     (*mutex_free)          (GMutex              *mutex);
+  GCond*   (*cond_new)            (void);
+  void     (*cond_signal)         (GCond               *cond);
+  void     (*cond_broadcast)      (GCond               *cond);
+  void     (*cond_wait)           (GCond               *cond,
+                                  GMutex               *mutex);
+  gboolean (*cond_timed_wait)     (GCond               *cond,
+                                  GMutex               *mutex, 
+                                  GTimeVal             *end_time);
+  void      (*cond_free)          (GCond               *cond);
+  GPrivate* (*private_new)        (GDestroyNotify       destructor);
+  gpointer  (*private_get)        (GPrivate            *private_key);
+  void      (*private_set)        (GPrivate            *private_key,
+                                  gpointer              data);
+  gpointer  (*thread_create)      (GThreadFunc                  thread_func,
+                                  gpointer              arg,
+                                  gulong                stack_size,
+                                  gboolean              joinable,
+                                  gboolean              bound,
+                                  GThreadPriority       priority);
+  void      (*thread_yield)       (void);
+  void      (*thread_join)        (gpointer             thread);
+  void      (*thread_exit)        (void);
+  void      (*thread_set_priority)(gpointer             thread, 
+                                  GThreadPriority       priority);
+  gpointer  (*thread_self)        (void);
 };
 
 GUTILS_C_VAR GThreadFunctions  g_thread_functions_for_glib_use;
@@ -2891,6 +2925,20 @@ GMutex*  g_static_mutex_get_mutex_impl   (GMutex **mutex);
                                                        (void) (private_key = \
                                                         (GPrivate*) (value)), \
                                                        (private_key, value))
+#define g_thread_yield()              G_THREAD_CF (thread_yield, (void)0, ())
+#define g_thread_exit()               G_THREAD_CF (thread_exit, (void)0, ())
+
+GThread* g_thread_create (GThreadFunc           thread_func,
+                         gpointer               arg,
+                         gulong                 stack_size,
+                         gboolean               joinable,
+                         gboolean               bound,
+                         GThreadPriority        priority);
+GThread* g_thread_self ();
+void g_thread_join (GThread* thread);
+void g_thread_set_priority (GThread* thread, 
+                           GThreadPriority priority);
+
 /* GStaticMutexes can be statically initialized with the value
  * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
  * much easier, than having to explicitly allocate the mutex before
@@ -2902,6 +2950,7 @@ GMutex*   g_static_mutex_get_mutex_impl   (GMutex **mutex);
     g_mutex_trylock (g_static_mutex_get_mutex (mutex))
 #define g_static_mutex_unlock(mutex) \
     g_mutex_unlock (g_static_mutex_get_mutex (mutex)) 
+
 struct _GStaticPrivate
 {
   guint index;
@@ -2911,6 +2960,51 @@ gpointer g_static_private_get (GStaticPrivate    *private_key);
 void     g_static_private_set (GStaticPrivate  *private_key, 
                               gpointer          data,
                               GDestroyNotify    notify);
+gpointer g_static_private_get_for_thread (GStaticPrivate *private_key,
+                                         GThread        *thread);
+void g_static_private_set_for_thread (GStaticPrivate *private_key, 
+                                     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
+{
+  GStaticMutex mutex; 
+  GCond *read_cond;
+  GCond *write_cond;
+  guint read_counter;
+  gboolean write;
+  guint want_to_write;
+};
+
+#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE }
+
+void      g_static_rw_lock_reader_lock    (GStaticRWLock* lock);
+gboolean  g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
+void      g_static_rw_lock_reader_unlock  (GStaticRWLock* lock);
+void      g_static_rw_lock_writer_lock    (GStaticRWLock* lock);
+gboolean  g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
+void      g_static_rw_lock_writer_unlock  (GStaticRWLock* lock);
+void      g_static_rw_lock_free (GStaticRWLock* lock);
 
 /* these are some convenience macros that expand to nothing if GLib
  * was configured with --disable-threads. for using StaticMutexes,
index 0725691..f5a8c47 100644 (file)
@@ -40,7 +40,6 @@ libglib_la_SOURCES = \
        gmain.c         \
        gmem.c          \
        gmessages.c     \
-       gmutex.c        \
        gnode.c         \
        gprimes.c       \
        gqueue.c        \
@@ -51,6 +50,7 @@ libglib_la_SOURCES = \
        gstack.c        \
        gstrfuncs.c     \
        gstring.c       \
+       gthread.c       \
        gtimer.c        \
        gtree.c         \
        gutils.c
index 2587368..0137c82 100644 (file)
@@ -1500,6 +1500,9 @@ void g_blow_chunks (void);
 
 /* Timer
  */
+
+#define G_MICROSEC 1000000
+
 GTimer* g_timer_new    (void);
 void   g_timer_destroy (GTimer  *timer);
 void   g_timer_start   (GTimer  *timer);
@@ -1507,7 +1510,7 @@ void      g_timer_stop    (GTimer  *timer);
 void   g_timer_reset   (GTimer  *timer);
 gdouble g_timer_elapsed (GTimer         *timer,
                         gulong  *microseconds);
-
+void    g_usleep        (gulong microseconds);
 
 /* String utility functions that modify a string argument or
  * return a constant string that must not be freed.
@@ -2367,7 +2370,6 @@ gsize        g_date_strftime              (gchar       *s,
                                            const gchar *format,
                                            GDate       *date);
 
-
 /* GRelation
  *
  * Indexed Relations.  Imagine a really simple table in a
@@ -2819,31 +2821,63 @@ gint            gwin_closedir   (DIR            *dir);
 
 /* GLib Thread support
  */
+
+typedef void           (*GThreadFunc)          (gpointer       value);
+
+typedef enum
+{
+    G_THREAD_PRIORITY_LOW,
+    G_THREAD_PRIORITY_NORMAL,
+    G_THREAD_PRIORITY_HIGH,
+    G_THREAD_PRIORITY_URGENT, 
+} GThreadPriority;
+
+typedef struct _GThread         GThread;
+struct  _GThread
+{
+  GThreadPriority priority;
+  gboolean bound;
+  gboolean joinable;
+};
+
 typedef struct _GMutex         GMutex;
 typedef struct _GCond          GCond;
 typedef struct _GPrivate       GPrivate;
 typedef struct _GStaticPrivate GStaticPrivate;
+
 typedef struct _GThreadFunctions GThreadFunctions;
 struct _GThreadFunctions
 {
-  GMutex*  (*mutex_new)       (void);
-  void     (*mutex_lock)      (GMutex          *mutex);
-  gboolean (*mutex_trylock)   (GMutex          *mutex);
-  void     (*mutex_unlock)    (GMutex          *mutex);
-  void     (*mutex_free)      (GMutex          *mutex);
-  GCond*   (*cond_new)        (void);
-  void     (*cond_signal)     (GCond           *cond);
-  void     (*cond_broadcast)  (GCond           *cond);
-  void     (*cond_wait)       (GCond           *cond,
-                              GMutex           *mutex);
-  gboolean (*cond_timed_wait) (GCond           *cond,
-                              GMutex           *mutex, 
-                              GTimeVal         *end_time);
-  void      (*cond_free)      (GCond           *cond);
-  GPrivate* (*private_new)    (GDestroyNotify   destructor);
-  gpointer  (*private_get)    (GPrivate                *private_key);
-  void      (*private_set)    (GPrivate                *private_key,
-                              gpointer          data);
+  GMutex*  (*mutex_new)           (void);
+  void     (*mutex_lock)          (GMutex              *mutex);
+  gboolean (*mutex_trylock)       (GMutex              *mutex);
+  void     (*mutex_unlock)        (GMutex              *mutex);
+  void     (*mutex_free)          (GMutex              *mutex);
+  GCond*   (*cond_new)            (void);
+  void     (*cond_signal)         (GCond               *cond);
+  void     (*cond_broadcast)      (GCond               *cond);
+  void     (*cond_wait)           (GCond               *cond,
+                                  GMutex               *mutex);
+  gboolean (*cond_timed_wait)     (GCond               *cond,
+                                  GMutex               *mutex, 
+                                  GTimeVal             *end_time);
+  void      (*cond_free)          (GCond               *cond);
+  GPrivate* (*private_new)        (GDestroyNotify       destructor);
+  gpointer  (*private_get)        (GPrivate            *private_key);
+  void      (*private_set)        (GPrivate            *private_key,
+                                  gpointer              data);
+  gpointer  (*thread_create)      (GThreadFunc                  thread_func,
+                                  gpointer              arg,
+                                  gulong                stack_size,
+                                  gboolean              joinable,
+                                  gboolean              bound,
+                                  GThreadPriority       priority);
+  void      (*thread_yield)       (void);
+  void      (*thread_join)        (gpointer             thread);
+  void      (*thread_exit)        (void);
+  void      (*thread_set_priority)(gpointer             thread, 
+                                  GThreadPriority       priority);
+  gpointer  (*thread_self)        (void);
 };
 
 GUTILS_C_VAR GThreadFunctions  g_thread_functions_for_glib_use;
@@ -2891,6 +2925,20 @@ GMutex*  g_static_mutex_get_mutex_impl   (GMutex **mutex);
                                                        (void) (private_key = \
                                                         (GPrivate*) (value)), \
                                                        (private_key, value))
+#define g_thread_yield()              G_THREAD_CF (thread_yield, (void)0, ())
+#define g_thread_exit()               G_THREAD_CF (thread_exit, (void)0, ())
+
+GThread* g_thread_create (GThreadFunc           thread_func,
+                         gpointer               arg,
+                         gulong                 stack_size,
+                         gboolean               joinable,
+                         gboolean               bound,
+                         GThreadPriority        priority);
+GThread* g_thread_self ();
+void g_thread_join (GThread* thread);
+void g_thread_set_priority (GThread* thread, 
+                           GThreadPriority priority);
+
 /* GStaticMutexes can be statically initialized with the value
  * G_STATIC_MUTEX_INIT, and then they can directly be used, that is
  * much easier, than having to explicitly allocate the mutex before
@@ -2902,6 +2950,7 @@ GMutex*   g_static_mutex_get_mutex_impl   (GMutex **mutex);
     g_mutex_trylock (g_static_mutex_get_mutex (mutex))
 #define g_static_mutex_unlock(mutex) \
     g_mutex_unlock (g_static_mutex_get_mutex (mutex)) 
+
 struct _GStaticPrivate
 {
   guint index;
@@ -2911,6 +2960,51 @@ gpointer g_static_private_get (GStaticPrivate    *private_key);
 void     g_static_private_set (GStaticPrivate  *private_key, 
                               gpointer          data,
                               GDestroyNotify    notify);
+gpointer g_static_private_get_for_thread (GStaticPrivate *private_key,
+                                         GThread        *thread);
+void g_static_private_set_for_thread (GStaticPrivate *private_key, 
+                                     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
+{
+  GStaticMutex mutex; 
+  GCond *read_cond;
+  GCond *write_cond;
+  guint read_counter;
+  gboolean write;
+  guint want_to_write;
+};
+
+#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE }
+
+void      g_static_rw_lock_reader_lock    (GStaticRWLock* lock);
+gboolean  g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
+void      g_static_rw_lock_reader_unlock  (GStaticRWLock* lock);
+void      g_static_rw_lock_writer_lock    (GStaticRWLock* lock);
+gboolean  g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
+void      g_static_rw_lock_writer_unlock  (GStaticRWLock* lock);
+void      g_static_rw_lock_free (GStaticRWLock* lock);
 
 /* these are some convenience macros that expand to nothing if GLib
  * was configured with --disable-threads. for using StaticMutexes,
diff --git a/glib/gthread.c b/glib/gthread.c
new file mode 100644 (file)
index 0000000..0aaef25
--- /dev/null
@@ -0,0 +1,535 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gmutex.c: MT safety related functions
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *                Owen Taylor
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/* 
+ * MT safe
+ */
+
+#include "glib.h"
+#include <unistd.h>
+
+typedef struct _GRealThread GRealThread;
+
+struct  _GRealThread
+{
+  GThread thread;
+  GThreadFunc func;
+  gpointer arg;
+  gpointer system_thread;
+  gpointer private_data;
+};
+
+typedef struct _GStaticPrivateNode GStaticPrivateNode;
+
+struct _GStaticPrivateNode
+{
+  gpointer       data;
+  GDestroyNotify destroy;
+};
+
+static void g_thread_cleanup (gpointer data);
+static void g_thread_fail (void);
+
+/* Global variables */
+
+gboolean g_thread_use_default_impl = TRUE;
+gboolean g_threads_got_initialized = FALSE;
+
+GThreadFunctions g_thread_functions_for_glib_use = {
+  (GMutex*(*)())g_thread_fail,                 /* mutex_new */
+  NULL,                                        /* mutex_lock */
+  NULL,                                        /* mutex_trylock */
+  NULL,                                        /* mutex_unlock */
+  NULL,                                        /* mutex_free */
+  (GCond*(*)())g_thread_fail,                  /* cond_new */
+  NULL,                                        /* cond_signal */
+  NULL,                                        /* cond_broadcast */
+  NULL,                                        /* cond_wait */
+  NULL,                                        /* cond_timed_wait  */
+  NULL,                                        /* cond_free */
+  (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
+  NULL,                                        /* private_get */
+  NULL,                                        /* private_set */
+  (gpointer(*)(GThreadFunc, gpointer, gulong, 
+              gboolean, gboolean, 
+              GThreadPriority))g_thread_fail, /* thread_create */
+  NULL,                                        /* thread_yield */
+  NULL,                                        /* thread_join */
+  NULL,                                        /* thread_exit */
+  NULL,                                        /* thread_set_priority */
+  NULL                                         /* thread_self */
+}; 
+
+/* Local data */
+
+static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
+static GMutex   *g_thread_specific_mutex = NULL;
+static GPrivate *g_thread_specific_private = NULL;
+
+/* This must be called only once, before any threads are created.
+ * It will only be called from g_thread_init() in -lgthread.
+ */
+void
+g_mutex_init (void)
+{
+  gpointer private_old;
+  /* We let the main thread (the one that calls g_thread_init) inherit
+   * the data, that it set before calling g_thread_init
+   */
+  private_old = g_thread_specific_private;
+
+  g_thread_specific_private = g_private_new (g_thread_cleanup);
+
+  /* we can not use g_private_set here, as g_threads_got_initialized is not
+   * yet set TRUE, whereas the private_set function is already set.
+   */
+  g_thread_functions_for_glib_use.private_set (g_thread_specific_private, 
+                                              private_old);
+
+  g_mutex_protect_static_mutex_allocation = g_mutex_new();
+  g_thread_specific_mutex = g_mutex_new();
+  
+}
+
+GMutex *
+g_static_mutex_get_mutex_impl (GMutex** mutex)
+{
+  if (!g_thread_supported ())
+    return NULL;
+
+  g_assert (g_mutex_protect_static_mutex_allocation);
+
+  g_mutex_lock (g_mutex_protect_static_mutex_allocation);
+
+  if (!(*mutex)) 
+    *mutex = g_mutex_new(); 
+
+  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)
+{
+  return g_static_private_get_for_thread (private_key, g_thread_self ());
+}
+
+gpointer
+g_static_private_get_for_thread (GStaticPrivate *private_key,
+                                GThread        *thread)
+{
+  GArray *array;
+  GRealThread *self = (GRealThread*) thread;
+
+  g_return_val_if_fail (thread, NULL);
+
+  array = self->private_data;
+  if (!array)
+    return NULL;
+
+  if (!private_key->index)
+    return NULL;
+  else if (private_key->index <= array->len)
+    return g_array_index (array, GStaticPrivateNode, private_key->index - 1).data;
+  else
+    return NULL;
+}
+
+void
+g_static_private_set (GStaticPrivate *private_key, 
+                     gpointer        data,
+                     GDestroyNotify  notify)
+{
+  g_static_private_set_for_thread (private_key, g_thread_self (), 
+                                  data, notify);
+}
+
+void
+g_static_private_set_for_thread (GStaticPrivate *private_key, 
+                                GThread        *thread,
+                                gpointer        data,
+                                GDestroyNotify  notify)
+{
+  GArray *array;
+  GRealThread *self =(GRealThread*) thread;
+  static guint next_index = 0;
+  GStaticPrivateNode *node;
+
+  g_return_if_fail (thread);
+  
+  array = self->private_data;
+  if (!array)
+    {
+      array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
+      self->private_data = array;
+    }
+
+  if (!private_key->index)
+    {
+      g_mutex_lock (g_thread_specific_mutex);
+
+      if (!private_key->index)
+       private_key->index = ++next_index;
+
+      g_mutex_unlock (g_thread_specific_mutex);
+    }
+
+  if (private_key->index > array->len)
+    g_array_set_size (array, private_key->index);
+
+  node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
+  if (node->destroy)
+    {
+      gpointer ddata = node->data;
+      GDestroyNotify ddestroy = node->destroy;
+
+      node->data = data;
+      node->destroy = notify;
+
+      ddestroy (ddata);
+    }
+  else
+    {
+      node->data = data;
+      node->destroy = notify;
+    }
+}
+
+static void
+g_thread_cleanup (gpointer data)
+{
+  if (data)
+    {
+      GRealThread* thread = data;
+      if (thread->private_data)
+       {
+         GArray* array = thread->private_data;
+         guint i;
+         
+         for (i = 0; i < array->len; i++ )
+           {
+             GStaticPrivateNode *node = 
+               &g_array_index (array, GStaticPrivateNode, i);
+             if (node->destroy)
+               node->destroy (node->data);
+           }
+         g_array_free (array, TRUE);
+       }
+      /* We only free the thread structure, if it isn't joinable. If
+         it is, the structure is freed in g_thread_join */
+      if (!thread->thread.joinable)
+       {
+         /* Just to make sure, this isn't used any more */
+         thread->system_thread = NULL;
+         g_free (thread);
+       }
+    }
+}
+
+static void
+g_thread_fail (void)
+{
+  g_error ("The thread system is not yet initialized.");
+}
+
+G_LOCK_DEFINE_STATIC (g_thread_create);
+
+static void 
+g_thread_create_proxy (gpointer data)
+{
+  GRealThread* thread = data;
+
+  g_assert (data);
+
+  /* the lock makes sure, that thread->system_thread is written,
+     before thread->func is called. See g_thread_create */
+
+  G_LOCK (g_thread_create);
+  g_private_set (g_thread_specific_private, data);
+  G_UNLOCK (g_thread_create);
+
+  thread->func (thread->arg);
+}
+
+GThread* 
+g_thread_create (GThreadFunc            thread_func,
+                gpointer                arg,
+                gulong                  stack_size,
+                gboolean                joinable,
+                gboolean                bound,
+                GThreadPriority         priority)
+{
+  GRealThread* result = g_new0 (GRealThread,1);
+
+  g_return_val_if_fail (thread_func, NULL);
+  
+  result->thread.joinable = joinable;
+  result->thread.bound = bound;
+  result->thread.priority = priority;
+  result->func = thread_func;
+  result->arg = arg;
+  G_LOCK (g_thread_create);
+  result->system_thread = G_THREAD_UF (thread_create, (g_thread_create_proxy, 
+                                                      result, stack_size, 
+                                                      joinable, bound, 
+                                                      priority));
+  G_UNLOCK (g_thread_create);
+  return (GThread*) result;
+}
+
+void 
+g_thread_join (GThread* thread)
+{
+  GRealThread* real = (GRealThread*) thread;
+
+  g_return_if_fail (thread);
+  g_return_if_fail (thread->joinable);
+  g_return_if_fail (real->system_thread);
+
+  G_THREAD_UF (thread_join, (real->system_thread));
+
+  /* Just to make sure, this isn't used any more */
+  thread->joinable = 0;
+  real->system_thread = NULL;
+
+  /* the thread structure for non-joinable threads is freed upon
+     thread end. We free the memory here. This will leave loose end,
+     if a joinable thread is not joined. */
+
+  g_free (thread);
+}
+
+void
+g_thread_set_priority (GThread* thread, 
+                      GThreadPriority priority)
+{
+  GRealThread* real = (GRealThread*) thread;
+
+  g_return_if_fail (thread);
+  g_return_if_fail (real->system_thread);
+
+  thread->priority = priority;
+  G_THREAD_CF (thread_set_priority, (void)0, (real->system_thread, priority));
+}
+
+GThread*
+g_thread_self()
+{
+  GRealThread* thread = g_private_get (g_thread_specific_private);
+
+  if (!thread)
+    {  
+      /* If no thread data is available, provide and set one.  This
+         can happen for the main thread and for threads, that are not
+         created by glib. */
+      thread = g_new (GRealThread,1);
+      thread->thread.joinable = FALSE; /* This is a save guess */
+      thread->thread.bound = TRUE; /* This isn't important at all */
+      thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
+                                                            just a guess */
+      thread->func = NULL;
+      thread->arg = NULL;
+      thread->system_thread = NULL;
+      thread->private_data = NULL;
+      g_private_set (g_thread_specific_private, thread);
+    }
+     
+  if (g_thread_supported () && !thread->system_thread)
+    {
+      thread->system_thread = g_thread_functions_for_glib_use.thread_self();
+    }
+
+  return (GThread*)thread;
+}
+
+static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
+{
+  if (!*cond)
+      *cond = g_cond_new ();
+  g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
+}
+
+static void inline g_static_rw_lock_signal (GStaticRWLock* lock)
+{
+  if (lock->want_to_write && lock->write_cond)
+    g_cond_signal (lock->write_cond);
+  else if (lock->read_cond)
+    g_cond_signal (lock->read_cond);
+}
+
+void g_static_rw_lock_reader_lock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  while (lock->write || lock->want_to_write) 
+    g_static_rw_lock_wait (&lock->read_cond, &lock->mutex);
+  lock->read_counter++;
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
+{
+  gboolean ret_val = FALSE;
+
+  g_return_val_if_fail (lock, FALSE);
+
+  if (!g_threads_got_initialized)
+    return TRUE;
+
+  g_static_mutex_lock (&lock->mutex);
+  if (!lock->write && !lock->want_to_write)
+    {
+      lock->read_counter++;
+      ret_val = TRUE;
+    }
+  g_static_mutex_unlock (&lock->mutex);
+  return ret_val;
+}
+
+void g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->read_counter--;
+  g_static_rw_lock_signal (lock);
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+void g_static_rw_lock_writer_lock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->want_to_write++;
+  while (lock->write || lock->read_counter)
+    g_static_rw_lock_wait (&lock->write_cond, &lock->mutex);
+  lock->want_to_write--;
+  lock->write = TRUE;
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
+{
+  gboolean ret_val = FALSE;
+
+  g_return_val_if_fail (lock, FALSE);
+  
+  if (!g_threads_got_initialized)
+    return TRUE;
+
+  g_static_mutex_lock (&lock->mutex);
+  if (!lock->write && !lock->read_counter)
+    {
+      lock->write = TRUE;
+      ret_val = TRUE;
+    }
+  g_static_mutex_unlock (&lock->mutex);
+  return ret_val;
+}
+
+void g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+  
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->write = FALSE; 
+  g_static_rw_lock_signal (lock);
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+void g_static_rw_lock_free (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+  
+  if (lock->read_cond)
+    g_cond_free (lock->read_cond);
+  if (lock->write_cond)
+    g_cond_free (lock->write_cond);
+  
+}
+
index 854ec67..0e61f63 100644 (file)
@@ -176,7 +176,7 @@ g_timer_elapsed (GTimer *timer,
 
   if (rtimer->start.tv_usec > rtimer->end.tv_usec)
     {
-      rtimer->end.tv_usec += 1000000;
+      rtimer->end.tv_usec += G_MICROSEC;
       rtimer->end.tv_sec--;
     }
 
@@ -191,3 +191,13 @@ g_timer_elapsed (GTimer *timer,
 
   return total;
 }
+
+void
+g_usleep (gulong microseconds)
+{
+  struct timeval tv;
+  tv.tv_sec = microseconds / G_MICROSEC;
+  tv.tv_usec = microseconds % G_MICROSEC;
+  select(0, NULL, NULL, NULL, &tv);
+}
+
index fd468f7..1c80b15 100644 (file)
@@ -478,8 +478,8 @@ g_get_any_init (void)
                 */
                if (error == 0 || error == ENOENT)
                  {
-                   g_warning ("getpwuid_r(): failed due to: No such user %d.",
-                              getuid ());
+                   g_warning ("getpwuid_r(): failed due to: 
+                              "No such user: %lu.", (unsigned long)getuid ());
                    break;
                  }
                if (bufsize > 32 * 1024)
diff --git a/gmutex.c b/gmutex.c
deleted file mode 100644 (file)
index d2fe57a..0000000
--- a/gmutex.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/* GLIB - Library of useful routines for C programming
- * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * gmutex.c: MT safety related functions
- * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
- *                Owen Taylor
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/*
- * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
- * file for a list of people on the GLib Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GLib at ftp://ftp.gtk.org/pub/gtk/. 
- */
-
-/* 
- * MT safe
- */
-
-#include "glib.h"
-
-typedef struct _GStaticPrivateNode GStaticPrivateNode;
-
-struct _GStaticPrivateNode
-{
-  gpointer       data;
-  GDestroyNotify destroy;
-};
-
-static void g_static_private_free_data (gpointer data);
-static void g_thread_fail (void);
-
-/* Global variables */
-
-gboolean g_thread_use_default_impl = TRUE;
-gboolean g_threads_got_initialized = FALSE;
-
-GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use = {
-  (GMutex*(*)())g_thread_fail,                 /* mutex_new */
-  NULL,                                        /* mutex_lock */
-  NULL,                                        /* mutex_trylock */
-  NULL,                                        /* mutex_unlock */
-  NULL,                                        /* mutex_free */
-  (GCond*(*)())g_thread_fail,                  /* cond_new */
-  NULL,                                        /* cond_signal */
-  NULL,                                        /* cond_broadcast */
-  NULL,                                        /* cond_wait */
-  NULL,                                        /* cond_timed_wait  */
-  NULL,                                        /* cond_free */
-  (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
-  NULL,                                        /* private_get */
-  NULL,                                        /* private_set */
-}; 
-
-/* Local data */
-
-static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
-static GMutex   *g_thread_specific_mutex = NULL;
-static GPrivate *g_thread_specific_private = NULL;
-
-/* This must be called only once, before any threads are created.
- * It will only be called from g_thread_init() in -lgthread.
- */
-void
-g_mutex_init (void)
-{
-  /* We let the main thread (the one that calls g_thread_init) inherit
-   * the data, that it set before calling g_thread_init
-   */
-  gpointer private_old = g_thread_specific_private;
-
-  g_thread_specific_private = g_private_new (g_static_private_free_data);
-
-  /* we can not use g_private_set here, as g_threads_got_initialized is not
-   * yet set TRUE, whereas the private_set function is already set.
-   */
-  g_thread_functions_for_glib_use.private_set (g_thread_specific_private, 
-                                              private_old);
-
-  g_mutex_protect_static_mutex_allocation = g_mutex_new();
-  g_thread_specific_mutex = g_mutex_new();
-}
-
-GMutex *
-g_static_mutex_get_mutex_impl (GMutex** mutex)
-{
-  if (!g_thread_supported ())
-    return NULL;
-
-  g_assert (g_mutex_protect_static_mutex_allocation);
-
-  g_mutex_lock (g_mutex_protect_static_mutex_allocation);
-
-  if (!(*mutex)) 
-    *mutex = g_mutex_new(); 
-
-  g_mutex_unlock (g_mutex_protect_static_mutex_allocation);
-  
-  return *mutex;
-}
-
-gpointer
-g_static_private_get (GStaticPrivate *private_key)
-{
-  GArray *array;
-
-  array = g_private_get (g_thread_specific_private);
-  if (!array)
-    return NULL;
-
-  if (!private_key->index)
-    return NULL;
-  else if (private_key->index <= array->len)
-    return g_array_index (array, GStaticPrivateNode, private_key->index - 1).data;
-  else
-    return NULL;
-}
-
-void
-g_static_private_set (GStaticPrivate *private_key, 
-                     gpointer        data,
-                     GDestroyNotify  notify)
-{
-  GArray *array;
-  static guint next_index = 0;
-  GStaticPrivateNode *node;
-  
-  array = g_private_get (g_thread_specific_private);
-  if (!array)
-    {
-      array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
-      g_private_set (g_thread_specific_private, array);
-    }
-
-  if (!private_key->index)
-    {
-      g_mutex_lock (g_thread_specific_mutex);
-
-      if (!private_key->index)
-       private_key->index = ++next_index;
-
-      g_mutex_unlock (g_thread_specific_mutex);
-    }
-
-  if (private_key->index > array->len)
-    g_array_set_size (array, private_key->index);
-
-  node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
-  if (node->destroy)
-    {
-      gpointer ddata = node->data;
-      GDestroyNotify ddestroy = node->destroy;
-
-      node->data = data;
-      node->destroy = notify;
-
-      ddestroy (ddata);
-    }
-  else
-    {
-      node->data = data;
-      node->destroy = notify;
-    }
-}
-
-static void
-g_static_private_free_data (gpointer data)
-{
-  if (data)
-    {
-      GArray* array = data;
-      guint i;
-      
-      for (i = 0; i < array->len; i++ )
-       {
-         GStaticPrivateNode *node = &g_array_index (array, GStaticPrivateNode, i);
-         if (node->destroy)
-           node->destroy (node->data);
-       }
-    }
-}
-
-static void
-g_thread_fail (void)
-{
-  g_error ("The thread system is not yet initialized.");
-}
diff --git a/gthread.c b/gthread.c
new file mode 100644 (file)
index 0000000..0aaef25
--- /dev/null
+++ b/gthread.c
@@ -0,0 +1,535 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gmutex.c: MT safety related functions
+ * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
+ *                Owen Taylor
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/* 
+ * MT safe
+ */
+
+#include "glib.h"
+#include <unistd.h>
+
+typedef struct _GRealThread GRealThread;
+
+struct  _GRealThread
+{
+  GThread thread;
+  GThreadFunc func;
+  gpointer arg;
+  gpointer system_thread;
+  gpointer private_data;
+};
+
+typedef struct _GStaticPrivateNode GStaticPrivateNode;
+
+struct _GStaticPrivateNode
+{
+  gpointer       data;
+  GDestroyNotify destroy;
+};
+
+static void g_thread_cleanup (gpointer data);
+static void g_thread_fail (void);
+
+/* Global variables */
+
+gboolean g_thread_use_default_impl = TRUE;
+gboolean g_threads_got_initialized = FALSE;
+
+GThreadFunctions g_thread_functions_for_glib_use = {
+  (GMutex*(*)())g_thread_fail,                 /* mutex_new */
+  NULL,                                        /* mutex_lock */
+  NULL,                                        /* mutex_trylock */
+  NULL,                                        /* mutex_unlock */
+  NULL,                                        /* mutex_free */
+  (GCond*(*)())g_thread_fail,                  /* cond_new */
+  NULL,                                        /* cond_signal */
+  NULL,                                        /* cond_broadcast */
+  NULL,                                        /* cond_wait */
+  NULL,                                        /* cond_timed_wait  */
+  NULL,                                        /* cond_free */
+  (GPrivate*(*)(GDestroyNotify))g_thread_fail, /* private_new */
+  NULL,                                        /* private_get */
+  NULL,                                        /* private_set */
+  (gpointer(*)(GThreadFunc, gpointer, gulong, 
+              gboolean, gboolean, 
+              GThreadPriority))g_thread_fail, /* thread_create */
+  NULL,                                        /* thread_yield */
+  NULL,                                        /* thread_join */
+  NULL,                                        /* thread_exit */
+  NULL,                                        /* thread_set_priority */
+  NULL                                         /* thread_self */
+}; 
+
+/* Local data */
+
+static GMutex   *g_mutex_protect_static_mutex_allocation = NULL;
+static GMutex   *g_thread_specific_mutex = NULL;
+static GPrivate *g_thread_specific_private = NULL;
+
+/* This must be called only once, before any threads are created.
+ * It will only be called from g_thread_init() in -lgthread.
+ */
+void
+g_mutex_init (void)
+{
+  gpointer private_old;
+  /* We let the main thread (the one that calls g_thread_init) inherit
+   * the data, that it set before calling g_thread_init
+   */
+  private_old = g_thread_specific_private;
+
+  g_thread_specific_private = g_private_new (g_thread_cleanup);
+
+  /* we can not use g_private_set here, as g_threads_got_initialized is not
+   * yet set TRUE, whereas the private_set function is already set.
+   */
+  g_thread_functions_for_glib_use.private_set (g_thread_specific_private, 
+                                              private_old);
+
+  g_mutex_protect_static_mutex_allocation = g_mutex_new();
+  g_thread_specific_mutex = g_mutex_new();
+  
+}
+
+GMutex *
+g_static_mutex_get_mutex_impl (GMutex** mutex)
+{
+  if (!g_thread_supported ())
+    return NULL;
+
+  g_assert (g_mutex_protect_static_mutex_allocation);
+
+  g_mutex_lock (g_mutex_protect_static_mutex_allocation);
+
+  if (!(*mutex)) 
+    *mutex = g_mutex_new(); 
+
+  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)
+{
+  return g_static_private_get_for_thread (private_key, g_thread_self ());
+}
+
+gpointer
+g_static_private_get_for_thread (GStaticPrivate *private_key,
+                                GThread        *thread)
+{
+  GArray *array;
+  GRealThread *self = (GRealThread*) thread;
+
+  g_return_val_if_fail (thread, NULL);
+
+  array = self->private_data;
+  if (!array)
+    return NULL;
+
+  if (!private_key->index)
+    return NULL;
+  else if (private_key->index <= array->len)
+    return g_array_index (array, GStaticPrivateNode, private_key->index - 1).data;
+  else
+    return NULL;
+}
+
+void
+g_static_private_set (GStaticPrivate *private_key, 
+                     gpointer        data,
+                     GDestroyNotify  notify)
+{
+  g_static_private_set_for_thread (private_key, g_thread_self (), 
+                                  data, notify);
+}
+
+void
+g_static_private_set_for_thread (GStaticPrivate *private_key, 
+                                GThread        *thread,
+                                gpointer        data,
+                                GDestroyNotify  notify)
+{
+  GArray *array;
+  GRealThread *self =(GRealThread*) thread;
+  static guint next_index = 0;
+  GStaticPrivateNode *node;
+
+  g_return_if_fail (thread);
+  
+  array = self->private_data;
+  if (!array)
+    {
+      array = g_array_new (FALSE, TRUE, sizeof (GStaticPrivateNode));
+      self->private_data = array;
+    }
+
+  if (!private_key->index)
+    {
+      g_mutex_lock (g_thread_specific_mutex);
+
+      if (!private_key->index)
+       private_key->index = ++next_index;
+
+      g_mutex_unlock (g_thread_specific_mutex);
+    }
+
+  if (private_key->index > array->len)
+    g_array_set_size (array, private_key->index);
+
+  node = &g_array_index (array, GStaticPrivateNode, private_key->index - 1);
+  if (node->destroy)
+    {
+      gpointer ddata = node->data;
+      GDestroyNotify ddestroy = node->destroy;
+
+      node->data = data;
+      node->destroy = notify;
+
+      ddestroy (ddata);
+    }
+  else
+    {
+      node->data = data;
+      node->destroy = notify;
+    }
+}
+
+static void
+g_thread_cleanup (gpointer data)
+{
+  if (data)
+    {
+      GRealThread* thread = data;
+      if (thread->private_data)
+       {
+         GArray* array = thread->private_data;
+         guint i;
+         
+         for (i = 0; i < array->len; i++ )
+           {
+             GStaticPrivateNode *node = 
+               &g_array_index (array, GStaticPrivateNode, i);
+             if (node->destroy)
+               node->destroy (node->data);
+           }
+         g_array_free (array, TRUE);
+       }
+      /* We only free the thread structure, if it isn't joinable. If
+         it is, the structure is freed in g_thread_join */
+      if (!thread->thread.joinable)
+       {
+         /* Just to make sure, this isn't used any more */
+         thread->system_thread = NULL;
+         g_free (thread);
+       }
+    }
+}
+
+static void
+g_thread_fail (void)
+{
+  g_error ("The thread system is not yet initialized.");
+}
+
+G_LOCK_DEFINE_STATIC (g_thread_create);
+
+static void 
+g_thread_create_proxy (gpointer data)
+{
+  GRealThread* thread = data;
+
+  g_assert (data);
+
+  /* the lock makes sure, that thread->system_thread is written,
+     before thread->func is called. See g_thread_create */
+
+  G_LOCK (g_thread_create);
+  g_private_set (g_thread_specific_private, data);
+  G_UNLOCK (g_thread_create);
+
+  thread->func (thread->arg);
+}
+
+GThread* 
+g_thread_create (GThreadFunc            thread_func,
+                gpointer                arg,
+                gulong                  stack_size,
+                gboolean                joinable,
+                gboolean                bound,
+                GThreadPriority         priority)
+{
+  GRealThread* result = g_new0 (GRealThread,1);
+
+  g_return_val_if_fail (thread_func, NULL);
+  
+  result->thread.joinable = joinable;
+  result->thread.bound = bound;
+  result->thread.priority = priority;
+  result->func = thread_func;
+  result->arg = arg;
+  G_LOCK (g_thread_create);
+  result->system_thread = G_THREAD_UF (thread_create, (g_thread_create_proxy, 
+                                                      result, stack_size, 
+                                                      joinable, bound, 
+                                                      priority));
+  G_UNLOCK (g_thread_create);
+  return (GThread*) result;
+}
+
+void 
+g_thread_join (GThread* thread)
+{
+  GRealThread* real = (GRealThread*) thread;
+
+  g_return_if_fail (thread);
+  g_return_if_fail (thread->joinable);
+  g_return_if_fail (real->system_thread);
+
+  G_THREAD_UF (thread_join, (real->system_thread));
+
+  /* Just to make sure, this isn't used any more */
+  thread->joinable = 0;
+  real->system_thread = NULL;
+
+  /* the thread structure for non-joinable threads is freed upon
+     thread end. We free the memory here. This will leave loose end,
+     if a joinable thread is not joined. */
+
+  g_free (thread);
+}
+
+void
+g_thread_set_priority (GThread* thread, 
+                      GThreadPriority priority)
+{
+  GRealThread* real = (GRealThread*) thread;
+
+  g_return_if_fail (thread);
+  g_return_if_fail (real->system_thread);
+
+  thread->priority = priority;
+  G_THREAD_CF (thread_set_priority, (void)0, (real->system_thread, priority));
+}
+
+GThread*
+g_thread_self()
+{
+  GRealThread* thread = g_private_get (g_thread_specific_private);
+
+  if (!thread)
+    {  
+      /* If no thread data is available, provide and set one.  This
+         can happen for the main thread and for threads, that are not
+         created by glib. */
+      thread = g_new (GRealThread,1);
+      thread->thread.joinable = FALSE; /* This is a save guess */
+      thread->thread.bound = TRUE; /* This isn't important at all */
+      thread->thread.priority = G_THREAD_PRIORITY_NORMAL; /* This is
+                                                            just a guess */
+      thread->func = NULL;
+      thread->arg = NULL;
+      thread->system_thread = NULL;
+      thread->private_data = NULL;
+      g_private_set (g_thread_specific_private, thread);
+    }
+     
+  if (g_thread_supported () && !thread->system_thread)
+    {
+      thread->system_thread = g_thread_functions_for_glib_use.thread_self();
+    }
+
+  return (GThread*)thread;
+}
+
+static void inline g_static_rw_lock_wait (GCond** cond, GStaticMutex* mutex)
+{
+  if (!*cond)
+      *cond = g_cond_new ();
+  g_cond_wait (*cond, g_static_mutex_get_mutex (mutex));
+}
+
+static void inline g_static_rw_lock_signal (GStaticRWLock* lock)
+{
+  if (lock->want_to_write && lock->write_cond)
+    g_cond_signal (lock->write_cond);
+  else if (lock->read_cond)
+    g_cond_signal (lock->read_cond);
+}
+
+void g_static_rw_lock_reader_lock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  while (lock->write || lock->want_to_write) 
+    g_static_rw_lock_wait (&lock->read_cond, &lock->mutex);
+  lock->read_counter++;
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock)
+{
+  gboolean ret_val = FALSE;
+
+  g_return_val_if_fail (lock, FALSE);
+
+  if (!g_threads_got_initialized)
+    return TRUE;
+
+  g_static_mutex_lock (&lock->mutex);
+  if (!lock->write && !lock->want_to_write)
+    {
+      lock->read_counter++;
+      ret_val = TRUE;
+    }
+  g_static_mutex_unlock (&lock->mutex);
+  return ret_val;
+}
+
+void g_static_rw_lock_reader_unlock  (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->read_counter--;
+  g_static_rw_lock_signal (lock);
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+void g_static_rw_lock_writer_lock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->want_to_write++;
+  while (lock->write || lock->read_counter)
+    g_static_rw_lock_wait (&lock->write_cond, &lock->mutex);
+  lock->want_to_write--;
+  lock->write = TRUE;
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock)
+{
+  gboolean ret_val = FALSE;
+
+  g_return_val_if_fail (lock, FALSE);
+  
+  if (!g_threads_got_initialized)
+    return TRUE;
+
+  g_static_mutex_lock (&lock->mutex);
+  if (!lock->write && !lock->read_counter)
+    {
+      lock->write = TRUE;
+      ret_val = TRUE;
+    }
+  g_static_mutex_unlock (&lock->mutex);
+  return ret_val;
+}
+
+void g_static_rw_lock_writer_unlock (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+  
+  if (!g_threads_got_initialized)
+    return;
+
+  g_static_mutex_lock (&lock->mutex);
+  lock->write = FALSE; 
+  g_static_rw_lock_signal (lock);
+  g_static_mutex_unlock (&lock->mutex);
+}
+
+void g_static_rw_lock_free (GStaticRWLock* lock)
+{
+  g_return_if_fail (lock);
+  
+  if (lock->read_cond)
+    g_cond_free (lock->read_cond);
+  if (lock->write_cond)
+    g_cond_free (lock->write_cond);
+  
+}
+
index f0592f3..51075f5 100644 (file)
@@ -1,3 +1,19 @@
+1999-06-17  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
+
+       * gthread-posix.c, gthread-solaris.c: Added the native
+       implementations for the GLib's extended thread support.
+
+       * gthread-nspr.c: Removed for good. NSPR is nothing we would want
+       to build upon.
+
+       * gthread.c: Renamed to gthread-impl.c to avoid confusion with
+       ../gthread.c (Formerly known as the file called gmutex.c)
+
+       * testgthread.c: Removed. The new and much extended tests are in
+       ../tests/thread-test.c.
+
+       * Makefile.am: Changed to reflect the changes above.
+
 1999-03-31  Sebastian Wilhelmi  <wilhelmi@ira.uka.de>
 
        * gthread-posix.c: Use the right default arguments for the
index 48a3bdf..9888fbf 100644 (file)
@@ -6,7 +6,6 @@ INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gthread \
 EXTRA_DIST =                           \
                gthread-posix.c         \
                gthread-solaris.c       \
-               gthread-nspr.c          \
                gthread-none.c          \
                gthread.def
 
@@ -16,12 +15,9 @@ top_builddir_full=`cd \$(top_builddir); pwd`
 
 lib_LTLIBRARIES = libgthread.la
 
-libgthread_la_SOURCES = gthread.c
+libgthread_la_SOURCES = gthread-impl.c
 libgthread_la_LDFLAGS = \
        -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
        -release $(LT_RELEASE)
 
 libgthread_la_LIBADD = @G_THREAD_LIBS_EXTRA@ @G_THREAD_LIBS@
-
-noinst_PROGRAMS = testgthread
-testgthread_LDADD = ../libglib.la libgthread.la
similarity index 76%
rename from gthread/gthread.c
rename to gthread/gthread-impl.c
index 57b75aa..726da39 100644 (file)
@@ -38,6 +38,9 @@
 #include <glib.h>
 
 static gboolean thread_system_already_initialized = FALSE;
+static gint g_thread_map_priority (GThreadPriority priority);
+static gint g_thread_min_priority = 0;
+static gint g_thread_max_priority = 0;
 
 #include G_THREAD_SOURCE
 
@@ -99,6 +102,15 @@ g_thread_init (GThreadFunctions* init)
        g_error ("The supplied thread function vector is invalid.");
     }
 
+  /* now do any initialization stuff required by the implementation,
+     but only if called with a NULL argument, of course. Otherwise it's
+     up to the user to do do. */
+
+#ifdef HAVE_G_THREAD_IMPL_INIT
+  if (g_thread_use_default_impl)
+    g_thread_impl_init();
+#endif
+
   /* now call the thread initialization functions of the different
    * glib modules. order does matter, g_mutex_init MUST come first.
    */
@@ -110,4 +122,22 @@ g_thread_init (GThreadFunctions* init)
    * all the thread functions
    */
   g_threads_got_initialized = TRUE;
+
+  /* we want the main thread to run with normal priority */
+  g_thread_set_priority (g_thread_self(), G_THREAD_PRIORITY_NORMAL);
+}
+
+static gint 
+g_thread_map_priority (GThreadPriority priority)
+{
+  guint procent;
+  switch (priority)
+    {
+    case G_THREAD_PRIORITY_LOW:             procent =   0; break;
+    default: case G_THREAD_PRIORITY_NORMAL: procent =  40; break;
+    case G_THREAD_PRIORITY_HIGH:            procent =  80; break;
+    case G_THREAD_PRIORITY_URGENT:          procent = 100; break;
+    }
+  return g_thread_min_priority + 
+    (g_thread_max_priority - g_thread_min_priority) * procent / 100;
 }
diff --git a/gthread/gthread-nspr.c b/gthread/gthread-nspr.c
deleted file mode 100644 (file)
index 2fe44b7..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* GLIB - Library of useful routines for C programming
- * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * gthread.c: nspr thread system implementation
- * Copyright 1998 Sebastian Wilhelmi; University of Karlsruhe
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/*
- * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
- * file for a list of people on the GLib Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GLib at ftp://ftp.gtk.org/pub/gtk/. 
- */
-
-/* 
- * MT safe
- */
-
-#include <prpdce.h>
-#include <prthread.h>
-#include <stdlib.h>
-
-#ifdef G_DISABLE_ASSERT
-
-#define STDERR_ASSERT(expr)
-
-#else /* G_DISABLE_ASSERT */
-
-#define STDERR_ASSERT(expr)                  G_STMT_START{      \
-     if (!(expr))                                               \
-       g_log (G_LOG_DOMAIN,                                     \
-              G_LOG_LEVEL_ERROR,                                \
-              "file %s: line %d: assertion failed: (%s)",       \
-              __FILE__,                                         \
-              __LINE__,                                         \
-              #expr);                   }G_STMT_END
-
-#endif /* G_DISABLE_ASSERT */
-
-/* NOTE: the functions g_mutex_lock and g_mutex_unlock may not use
-   functions from gmem.c and gmessages.c; */
-
-static gboolean
-g_mutex_trylock_nspr_impl (GMutex * mutex)
-{
-  PRStatus status = PRP_TryLock ((PRLock *) mutex);
-  if (status == PR_SUCCESS)
-    {
-      return TRUE;
-    }
-  return FALSE;
-}
-
-static void
-g_cond_wait_nspr_impl (GCond * cond,
-                      GMutex * entered_mutex)
-{
-  PRStatus status = PRP_NakedWait ((PRCondVar *) cond, 
-                                  (PRLock *) entered_mutex,
-                                  PR_INTERVAL_NO_TIMEOUT);
-  g_assert (status == PR_SUCCESS);
-}
-
-#define G_MICROSEC 1000000
-
-static gboolean
-g_cond_timed_wait_nspr_impl (GCond * cond,
-                            GMutex * entered_mutex,
-                            GTimeVal * abs_time)
-{
-  PRStatus status;
-  PRIntervalTime interval;
-  GTimeVal current_time;
-  glong microsecs;
-
-  g_return_val_if_fail (cond != NULL, FALSE);
-  g_return_val_if_fail (entered_mutex != NULL, FALSE);
-
-  g_get_current_time (&current_time);
-
-  if (abs_time->tv_sec < current_time.tv_sec ||
-      (abs_time->tv_sec == current_time.tv_sec &&
-       abs_time->tv_usec < current_time.tv_usec))
-    return FALSE;
-
-  interval = PR_SecondsToInterval (abs_time->tv_sec - current_time.tv_sec);
-  microsecs = abs_time->tv_usec - current_time.tv_usec;
-  if (microsecs < 0)
-    interval -= PR_MicrosecondsToInterval (-microsecs);
-  else
-    interval += PR_MicrosecondsToInterval (microsecs);
-
-  status = PRP_NakedWait ((PRCondVar *) cond, (PRLock *) entered_mutex,
-                         interval);
-
-  g_assert (status == PR_SUCCESS);
-
-  g_get_current_time (&current_time);
-
-  if (abs_time->tv_sec < current_time.tv_sec ||
-      (abs_time->tv_sec == current_time.tv_sec &&
-       abs_time->tv_usec < current_time.tv_usec))
-    return FALSE;
-  return TRUE;
-}
-
-typedef struct _GPrivateNSPRData GPrivateNSPRData;
-struct _GPrivateNSPRData
-  {
-    gpointer data;
-    GDestroyNotify destructor;
-  };
-
-typedef struct _GPrivateNSPR GPrivateNSPR;
-struct _GPrivateNSPR
-  {
-    PRUintn private_key;
-    GDestroyNotify destructor;
-  };
-
-static GPrivateNSPRData *
-g_private_nspr_data_constructor (GDestroyNotify destructor, gpointer data)
-{
-  /* we can not use g_new and friends, as they might use private data by
-     themself */
-  GPrivateNSPRData *private_key = malloc (sizeof (GPrivateNSPRData));
-  g_assert (private_key);
-  private_key->data = data;
-  private_key->destructor = destructor;
-
-  return private_key;
-}
-
-static void
-g_private_nspr_data_destructor (gpointer data)
-{
-  GPrivateNSPRData *private_key = data;
-  if (private_key->destructor && private_key->data)
-    (*private_key->destructor) (private_key->data);
-  free (private_key);
-}
-
-static GPrivate *
-g_private_new_nspr_impl (GDestroyNotify destructor)
-{
-  GPrivateNSPR *result = g_new (GPrivateNSPR, 1);
-  PRStatus status = PR_NewThreadPrivateIndex (&result->private_key,
-                                           g_private_nspr_data_destructor);
-  g_assert (status == PR_SUCCESS);
-
-  result->destructor = destructor;
-  return (GPrivate *) result;
-}
-
-/* NOTE: the functions g_private_get and g_private_set may not use
-   functions from gmem.c and gmessages.c */
-
-static GPrivateNSPRData *
-g_private_nspr_data_get (GPrivateNSPR * private_key)
-{
-  GPrivateNSPRData *data;
-
-  STDERR_ASSERT (private_key);
-
-  data = PR_GetThreadPrivate (private_key->private_key);
-  if (!data)
-    {
-      data = g_private_nspr_data_constructor (private_key->destructor, NULL);
-      STDERR_ASSERT (PR_SetThreadPrivate (private_key->private_key, data)
-                    == PR_SUCCESS);
-    }
-
-  return data;
-}
-
-static void
-g_private_set_nspr_impl (GPrivate * private_key, gpointer value)
-{
-  if (!private_key)
-    return;
-
-  g_private_nspr_data_get ((GPrivateNSPR *) private_key)->data = value;
-}
-
-static gpointer
-g_private_get_nspr_impl (GPrivate * private_key)
-{
-  if (!private_key)
-    return NULL;
-
-  return g_private_nspr_data_get ((GPrivateNSPR *) private_key)->data;
-}
-
-static GThreadFunctions g_thread_functions_for_glib_use_default =
-{
-  (GMutex * (*)())PR_NewLock,
-  (void (*)(GMutex *)) PR_Lock,
-  g_mutex_trylock_nspr_impl,
-  (void (*)(GMutex *)) PR_Unlock,
-  (void (*)(GMutex *)) PR_DestroyLock,
-  (GCond * (*)())PRP_NewNakedCondVar,
-  (void (*)(GCond *)) PRP_NakedNotify,
-  (void (*)(GCond *)) PRP_NakedBroadcast,
-  g_cond_wait_nspr_impl,
-  g_cond_timed_wait_nspr_impl,
-  (void (*)(GCond *)) PRP_DestroyNakedCondVar,
-  g_private_new_nspr_impl,
-  g_private_get_nspr_impl,
-  g_private_set_nspr_impl
-};
index 5611f87..e7c9462 100644 (file)
 #include <sys/time.h>
 #endif
 
+#if GLIB_SIZEOF_PTHREAD_T == 2
+#define PTHREAD_T_CAST_INT gint16
+#elif GLIB_SIZEOF_PTHREAD_T == 4
+#define PTHREAD_T_CAST_INT gint32
+#elif GLIB_SIZEOF_PTHREAD_T == 8 && defined(G_HAVE_GINT64)
+#define PTHREAD_T_CAST_INT gint64
+#else
+# error This should not happen. Contact the GLib team.
+#endif
+
+#define GPOINTER_TO_PTHREAD_T(x) ((pthread_t)(PTHREAD_T_CAST_INT)(x))
+#define PTHREAD_T_TO_GPOINTER(x) ((gpointer)(PTHREAD_T_CAST_INT)(x))
+
 #define posix_print_error( name, num )                          \
   g_error( "file %s: line %d (%s): error %s during %s",         \
            __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION,          \
 # define posix_check_for_error( what ) G_STMT_START{             \
     if( (what) == -1 ) { posix_print_error( what, errno ); }       \
     }G_STMT_END
+# define pthread_key_create(a, b) pthread_keycreate (a, b)
+# define pthread_attr_init(a) pthread_attr_create (a)
+# define pthread_attr_destroy(a) pthread_attr_delete (a)
+# define pthread_create(a, b, c, d) pthread_create(a, &b, c, d) 
 # define mutexattr_default (&pthread_mutexattr_default)
 # define condattr_default (&pthread_condattr_default)
 #else /* neither G_THREADS_IMPL_POSIX nor G_THREADS_IMPL_DCE are defined */
-# error This should not happen. Contact the GLb team.
+# error This should not happen. Contact the GLib team.
 #endif
 
+#define HAVE_G_THREAD_IMPL_INIT
+static void 
+g_thread_impl_init()
+{
+  g_thread_min_priority = POSIX_MIN_PRIORITY;
+  g_thread_max_priority = POSIX_MAX_PRIORITY;
+}
+
 static GMutex *
 g_mutex_new_posix_impl (void)
 {
@@ -179,7 +204,6 @@ g_private_set_posix_impl (GPrivate * private_key, gpointer value)
 {
   if (!private_key)
     return;
-
   pthread_setspecific (*(pthread_key_t *) private_key, value);
 }
 
@@ -197,9 +221,93 @@ g_private_get_posix_impl (GPrivate * private_key)
                                                private_key, &data));
     return data;
   }
-#endif 
+#endif
+}
+
+gpointer 
+g_thread_create_posix_impl (GThreadFunc thread_func, 
+                           gpointer arg, 
+                           gulong stack_size,
+                           gboolean joinable,
+                           gboolean bound,
+                           GThreadPriority priority)
+{     
+  pthread_t thread;
+  pthread_attr_t attr;
+  struct sched_param sched;
+
+  g_return_val_if_fail (thread_func, NULL);
+
+  posix_check_for_error (pthread_attr_init (&attr));
+  
+#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+  if (stack_size)
+      posix_check_for_error (pthread_attr_setstacksize (&attr, stack_size));
+#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
+
+  if (bound)
+     posix_check_for_error (pthread_attr_setscope (&attr, 
+                                                  PTHREAD_SCOPE_SYSTEM));
+  posix_check_for_error( pthread_attr_setdetachstate( &attr,
+          joinable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED ) );
+  
+#ifdef G_THREADS_IMPL_POSIX
+  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 */
+  posix_check_for_error 
+    (pthread_attr_setprio (&attr, g_thread_map_priority (priority));
+#endif
+
+  posix_check_for_error( pthread_create (&thread, &attr, 
+                                         (void* (*)(void*))thread_func,
+                                         arg) );
+  
+  posix_check_for_error( pthread_attr_destroy (&attr) );
+
+  return PTHREAD_T_TO_GPOINTER (thread);
+}
+
+void 
+g_thread_yield_posix_impl (void)
+{
+  POSIX_YIELD_FUNC;
+}
+
+void
+g_thread_join_posix_impl (gpointer thread)
+{     
+  gpointer ignore;
+  posix_check_for_error (pthread_join (GPOINTER_TO_PTHREAD_T (thread), 
+                                      &ignore));
+}
+
+void 
+g_thread_exit_posix_impl (void) 
+{
+  pthread_exit (NULL);
 }
 
+void
+g_thread_set_priority_posix_impl (gpointer thread, GThreadPriority priority)
+{
+  struct sched_param sched;
+  int policy;
+
+#ifdef G_THREADS_IMPL_POSIX
+  posix_check_for_error (pthread_getschedparam (GPOINTER_TO_PTHREAD_T (thread), 
+                                               &policy, &sched));
+  sched.sched_priority = g_thread_map_priority (priority);
+  posix_check_for_error (pthread_setschedparam (GPOINTER_TO_PTHREAD_T (thread), 
+                                               policy, &sched));
+#else /* G_THREADS_IMPL_DCE */
+  posix_check_for_error (pthread_setprio (GPOINTER_TO_PTHREAD_T (thread), 
+                                         g_thread_map_priority (priority)));
+#endif
+}
+
+
 static GThreadFunctions g_thread_functions_for_glib_use_default =
 {
   g_mutex_new_posix_impl,
@@ -215,5 +323,11 @@ static GThreadFunctions g_thread_functions_for_glib_use_default =
   g_cond_free_posix_impl,
   g_private_new_posix_impl,
   g_private_get_posix_impl,
-  g_private_set_posix_impl
+  g_private_set_posix_impl,
+  g_thread_create_posix_impl,
+  g_thread_yield_posix_impl,
+  g_thread_join_posix_impl,
+  g_thread_exit_posix_impl,
+  g_thread_set_priority_posix_impl,
+  (gpointer (*)())pthread_self
 };
index 4d9c375..1c189b2 100644 (file)
   if( error ) { solaris_print_error( what, error ); }           \
   }G_STMT_END
 
+#define HAVE_G_THREAD_IMPL_INIT
+static void 
+g_thread_impl_init()
+{
+  g_thread_min_priority = 0;
+  g_thread_max_priority = 127;
+}
+
 static GMutex *
 g_mutex_new_solaris_impl (void)
 {
@@ -165,6 +173,54 @@ g_private_get_solaris_impl (GPrivate * private_key)
   return result;
 }
 
+void
+g_thread_set_priority_solaris_impl (gpointer thread, GThreadPriority priority)
+{
+  solaris_check_for_error (thr_setprio (GPOINTER_TO_INT (thread),  
+                                       g_thread_map_priority (priority)));
+}
+
+gpointer 
+g_thread_create_solaris_impl (GThreadFunc thread_func, 
+                             gpointer arg, 
+                             gulong stack_size,
+                             gboolean joinable,
+                             gboolean bound,
+                             GThreadPriority priority)
+{     
+  thread_t thread;
+  long flags = (bound ? THR_BOUND : 0) | (joinable ? 0: THR_DETACHED);
+  
+  g_return_val_if_fail (thread_func, NULL);
+  
+  solaris_check_for_error (thr_create (NULL, stack_size,  
+                                      (void* (*)(void*))thread_func,
+                                      arg, flags, &thread));
+  
+  g_thread_set_priority_solaris_impl (GINT_TO_POINTER (thread), priority);
+
+  return GINT_TO_POINTER (thread);
+}
+
+void 
+g_thread_yield_solaris_impl (void)
+{
+  thr_yield ();
+}
+
+void
+g_thread_join_solaris_impl (gpointer thread)
+{     
+  gpointer ignore;
+  solaris_check_for_error (thr_join (GPOINTER_TO_INT (thread), NULL, &ignore));
+}
+
+void 
+g_thread_exit_solaris_impl (void) 
+{
+  thr_exit (NULL);
+}
+
 static GThreadFunctions g_thread_functions_for_glib_use_default =
 {
   g_mutex_new_solaris_impl,
@@ -180,5 +236,11 @@ static GThreadFunctions g_thread_functions_for_glib_use_default =
   g_cond_free_solaris_impl,
   g_private_new_solaris_impl,
   g_private_get_solaris_impl,
-  g_private_set_solaris_impl
+  g_private_set_solaris_impl,
+  g_thread_create_solaris_impl,
+  g_thread_yield_solaris_impl,
+  g_thread_join_solaris_impl,
+  g_thread_exit_solaris_impl,
+  g_thread_set_priority_solaris_impl,
+  (gpointer (*)())thr_self
 };
diff --git a/gthread/testgthread.c b/gthread/testgthread.c
deleted file mode 100644 (file)
index 72874cc..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-#include "config.h"
-
-#include <stdlib.h>
-
-#define main testglib_main
-#include <testglib.c>
-#undef main
-
-#define TEST_PRIVATE_THREADS 9
-#define TEST_PRIVATE_ROUNDS 5
-
-void
-test_mutexes (void)
-{
-  GMutex *mutex = NULL;
-  GCond *cond = NULL;
-  GStaticMutex static_mutex = G_STATIC_MUTEX_INIT;
-  G_LOCK_DEFINE (test_me);
-
-  if (g_thread_supported ())
-    {
-      mutex = g_mutex_new ();
-      cond = g_cond_new ();
-    }
-
-  g_mutex_lock (mutex);
-  g_mutex_unlock (mutex);
-
-  g_static_mutex_lock (&static_mutex);
-  g_static_mutex_unlock (&static_mutex);
-
-  g_cond_signal (cond);
-  g_cond_broadcast (cond);
-
-  G_LOCK (test_me);
-  G_UNLOCK (test_me);
-
-  if (g_thread_supported ())
-    {
-      g_cond_free (cond);
-      g_mutex_free (mutex);
-    }
-}
-
-#if defined(G_THREADS_IMPL_NSPR)       
-#warning "note, that you have to link with whatever library"
-#warning "nspr is building upon, it might otherwise (as on solaris) lead to"
-#warning "run time failure, as the mutex functions are defined in libc, but"
-#warning "as noops, that will make some nspr assertions fail."
-#include <prthread.h>
-
-gpointer
-new_thread (GHookFunc func, gpointer data)
-{
-  PRThread *thread = PR_CreateThread (PR_SYSTEM_THREAD, func, data,
-                                     PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
-                                     PR_JOINABLE_THREAD, 0);
-  return thread;
-}
-#define join_thread(thread) PR_JoinThread (thread)
-#define self_thread() PR_GetCurrentThread ()
-
-#elif defined(G_THREADS_IMPL_SOLARIS)  
-#include <thread.h>
-
-gpointer
-new_thread (GHookFunc func, gpointer data)
-{
-  thread_t thread;
-  thr_create (NULL, 0, (void *(*)(void *)) func, data, THR_BOUND, &thread);
-  return GUINT_TO_POINTER (thread);
-}
-#define join_thread(thread) \
-  thr_join ((thread_t)GPOINTER_TO_UINT (thread), NULL, NULL)
-#define self_thread()  GUINT_TO_POINTER (thr_self ())
-
-#elif defined(G_THREADS_IMPL_POSIX)
-#include <pthread.h>
-
-gpointer
-new_thread(GHookFunc func, gpointer data)
-{
-  pthread_t thread;
-  pthread_attr_t pthread_attr;
-  pthread_attr_init (&pthread_attr);
-  /* This is the default, it seems, so leave that out for now 
-     pthread_attr_setdetachstate (&pthread_attr, PTHREAD_CREATE_JOINABLE);
-  */
-  pthread_create (&thread, &pthread_attr, (void *(*)(void *)) func, data);
-  return GUINT_TO_POINTER (thread);
-}
-#define join_thread(thread) \
-  pthread_join ((pthread_t)GPOINTER_TO_UINT (thread), NULL)
-#define self_thread() GUINT_TO_POINTER (pthread_self ())
-
-#else /* we are not having a thread implementation, do nothing */
-
-#define new_thread(func,data) (NULL)
-#define join_thread(thread) ((void)0)
-#define self_thread() NULL
-
-#endif
-
-#define G_MICROSEC 1000000
-
-void
-wait_thread (double seconds)
-{
-  GMutex *mutex;
-  GCond *cond;
-  GTimeVal current_time;
-
-  g_get_current_time (&current_time);
-  mutex = g_mutex_new ();
-  cond = g_cond_new ();
-
-  current_time.tv_sec += (guint) seconds;
-  seconds -= (guint) seconds;
-  current_time.tv_usec += (guint) (seconds * G_MICROSEC);
-  while (current_time.tv_usec >= G_MICROSEC)
-    {
-      current_time.tv_usec -= G_MICROSEC;
-      current_time.tv_sec++;
-    }
-
-  g_mutex_lock (mutex);
-  g_cond_timed_wait (cond, mutex, &current_time);
-  g_mutex_unlock (mutex);
-
-  g_mutex_free (mutex);
-  g_cond_free (cond);
-}
-
-gpointer
-private_constructor (void)
-{
-  gpointer *result = g_new (gpointer, 2);
-  result[0] = 0;
-  result[1] = self_thread ();
-  g_print ("allocating data for the thread %p.\n", result[1]);
-  return result;
-}
-
-void
-private_destructor (gpointer data)
-{
-  gpointer *real = data;
-  g_print ("freeing data for the thread %p.\n", real[1]);
-  g_free (real);
-}
-
-GStaticPrivate private_key;
-
-void
-test_private_func (void *data)
-{
-  guint i = 0;
-  static unsigned int seed = 0;
-  if (!seed)
-    {
-      GTimeVal now;
-      g_get_current_time (&now);
-      seed = now.tv_usec;
-    }
-  wait_thread (1);
-  while (i < TEST_PRIVATE_ROUNDS)
-    {
-#ifdef HAVE_RAND_R
-      guint random_value = rand_r (&seed) % 10000;
-#else
-      guint random_value = rand() % 10000;
-#endif
-      guint *data = g_static_private_get (&private_key);
-      if (!data)
-       {
-         data = private_constructor ();
-         g_static_private_set (&private_key, data, private_destructor);
-       }
-      *data = random_value;
-      wait_thread (.2);
-      g_assert (*(guint *) g_static_private_get (&private_key) == random_value);
-      i++;
-    }
-}
-
-void
-test_private (void)
-{
-  int i;
-  gpointer threads[TEST_PRIVATE_THREADS];
-  for (i = 0; i < TEST_PRIVATE_THREADS; i++)
-    {
-      threads[i] = new_thread (test_private_func, GINT_TO_POINTER(i));
-    }
-  for (i = 0; i < TEST_PRIVATE_THREADS; i++)
-    {
-      join_thread (threads[i]);
-    }
-  g_print ("\n");
-}
-
-int
-main (void)
-{
-  test_mutexes ();
-
-  g_thread_init (NULL);
-
-  test_mutexes ();
-
-  test_private ();
-
-  /* later we might want to start n copies of that */
-  testglib_main (0, NULL);
-
-  return 0;
-}
index 854ec67..0e61f63 100644 (file)
--- a/gtimer.c
+++ b/gtimer.c
@@ -176,7 +176,7 @@ g_timer_elapsed (GTimer *timer,
 
   if (rtimer->start.tv_usec > rtimer->end.tv_usec)
     {
-      rtimer->end.tv_usec += 1000000;
+      rtimer->end.tv_usec += G_MICROSEC;
       rtimer->end.tv_sec--;
     }
 
@@ -191,3 +191,13 @@ g_timer_elapsed (GTimer *timer,
 
   return total;
 }
+
+void
+g_usleep (gulong microseconds)
+{
+  struct timeval tv;
+  tv.tv_sec = microseconds / G_MICROSEC;
+  tv.tv_usec = microseconds % G_MICROSEC;
+  select(0, NULL, NULL, NULL, &tv);
+}
+
index fd468f7..1c80b15 100644 (file)
--- a/gutils.c
+++ b/gutils.c
@@ -478,8 +478,8 @@ g_get_any_init (void)
                 */
                if (error == 0 || error == ENOENT)
                  {
-                   g_warning ("getpwuid_r(): failed due to: No such user %d.",
-                              getuid ());
+                   g_warning ("getpwuid_r(): failed due to: 
+                              "No such user: %lu.", (unsigned long)getuid ());
                    break;
                  }
                if (bufsize > 32 * 1024)
index b735dd9..2abdb0c 100644 (file)
@@ -20,7 +20,8 @@ TESTS = \
        string-test     \
        strfunc-test    \
        tree-test       \
-       type-test
+       type-test       \
+       thread-test
 
 noinst_PROGRAMS = $(TESTS)
 
@@ -39,6 +40,8 @@ string_test_LDADD = $(top_builddir)/libglib.la
 strfunc_test_LDADD = $(top_builddir)/libglib.la
 tree_test_LDADD = $(top_builddir)/libglib.la
 type_test_LDADD = $(top_builddir)/libglib.la
+thread_test_LDADD = $(top_builddir)/libglib.la \
+               $(top_builddir)/gthread/libgthread.la @G_THREAD_LIBS@
 
 makefile.msc: $(top_builddir)/config.status $(top_srcdir)/tests/makefile.msc.in
        cd $(top_builddir) && CONFIG_FILES=tests/$@ CONFIG_HEADERS= $(SHELL) ./config.status
diff --git a/tests/thread-test.c b/tests/thread-test.c
new file mode 100644 (file)
index 0000000..300e55e
--- /dev/null
@@ -0,0 +1,238 @@
+#include <glib.h>
+
+/* GMutex */
+
+static GMutex* test_g_mutex_mutex = NULL;
+static guint test_g_mutex_int = 0;
+
+static void
+test_g_mutex_thread (gpointer data)
+{
+  g_assert (GPOINTER_TO_INT (data) == 42);
+  g_assert (g_mutex_trylock (test_g_mutex_mutex) == FALSE);
+  g_mutex_lock (test_g_mutex_mutex);
+  g_assert (test_g_mutex_int == 42);
+  g_mutex_unlock (test_g_mutex_mutex);
+}
+
+static void
+test_g_mutex (void)
+{
+  GThread *thread;
+  test_g_mutex_mutex = g_mutex_new ();
+
+  g_assert (g_mutex_trylock (test_g_mutex_mutex));
+  thread = g_thread_create (test_g_mutex_thread, 
+                           GINT_TO_POINTER (42),
+                           0, TRUE, TRUE, G_THREAD_PRIORITY_NORMAL);
+  g_usleep (G_MICROSEC);
+  test_g_mutex_int = 42;
+  g_mutex_unlock (test_g_mutex_mutex);
+  g_thread_join (thread);
+  g_mutex_free (test_g_mutex_mutex);
+}
+
+/* GStaticRecMutex */
+
+static GStaticRecMutex test_g_static_rec_mutex_mutex = G_STATIC_REC_MUTEX_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) 
+           == FALSE);
+  g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
+  g_static_rec_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);
+}
+
+static void
+test_g_static_rec_mutex (void)
+{
+  GThread *thread;
+
+  g_assert (g_static_rec_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_usleep (G_MICROSEC);
+  test_g_static_rec_mutex_int = 41;
+  g_static_rec_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_usleep (G_MICROSEC);
+  g_static_rec_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_thread_join (thread);
+}
+
+/* GStaticPrivate */
+
+#define THREADS 10
+
+static GStaticPrivate test_g_static_private_private = G_STATIC_PRIVATE_INIT;
+static GStaticMutex test_g_static_private_mutex = G_STATIC_MUTEX_INIT;
+static guint test_g_static_private_counter = 0;
+
+static gpointer
+test_g_static_private_constructor (void)
+{
+  g_static_mutex_lock (&test_g_static_private_mutex);
+  test_g_static_private_counter++;
+  g_static_mutex_unlock (&test_g_static_private_mutex);  
+  return g_new (guint,1);
+}
+
+static void
+test_g_static_private_destructor (gpointer data)
+{
+  g_static_mutex_lock (&test_g_static_private_mutex);
+  test_g_static_private_counter--;
+  g_static_mutex_unlock (&test_g_static_private_mutex);  
+  g_free (data);
+}
+
+
+static void
+test_g_static_private_thread (gpointer data)
+{
+  guint number = GPOINTER_TO_INT (data);
+  guint i;
+  guint* private;
+  for (i = 0; i < 10; i++)
+    {
+      number = number * 11 + 1; /* A very simple and bad RNG ;-) */
+      private = g_static_private_get (&test_g_static_private_private);
+      if (!private || number % 7 > 3)
+       {
+         private = test_g_static_private_constructor ();
+         g_static_private_set (&test_g_static_private_private, private,
+                               test_g_static_private_destructor);
+       }
+      *private = number;
+      g_usleep (G_MICROSEC / 5);
+      g_assert (number == *private);
+    }
+}
+
+static void
+test_g_static_private (void)
+{
+  GThread *threads[THREADS];
+  guint i;
+  for (i = 0; i < THREADS; i++)
+    {
+      threads[i] = g_thread_create (test_g_static_private_thread, 
+                                   GINT_TO_POINTER (i),
+                                   0, TRUE, TRUE, 
+                                   G_THREAD_PRIORITY_NORMAL);      
+    }
+  for (i = 0; i < THREADS; i++)
+    {
+      g_thread_join (threads[i]);
+    }
+  g_assert (test_g_static_private_counter == 0); 
+}
+
+/* GStaticRWLock */
+
+/* -1 = writing; >0 = # of readers */
+static gint test_g_static_rw_lock_state = 0; 
+G_LOCK_DEFINE (test_g_static_rw_lock_state);
+
+static gboolean test_g_static_rw_lock_run = TRUE; 
+static GStaticRWLock test_g_static_rw_lock_lock = G_STATIC_RW_LOCK_INIT;
+
+static void
+test_g_static_rw_lock_thread (gpointer data)
+{
+  while (test_g_static_rw_lock_run)
+    {
+      if (g_random_double() > .2) /* I'm a reader */
+       {
+         
+         if (g_random_double() > .2) /* I'll block */
+           g_static_rw_lock_reader_lock (&test_g_static_rw_lock_lock);
+         else /* I'll only try */
+           if (!g_static_rw_lock_reader_trylock (&test_g_static_rw_lock_lock))
+             continue;
+         G_LOCK (test_g_static_rw_lock_state);
+         g_assert (test_g_static_rw_lock_state >= 0);
+         test_g_static_rw_lock_state++;
+         G_UNLOCK (test_g_static_rw_lock_state);
+
+         g_usleep (10);
+
+         G_LOCK (test_g_static_rw_lock_state);
+         test_g_static_rw_lock_state--;
+         G_UNLOCK (test_g_static_rw_lock_state);
+
+         g_static_rw_lock_reader_unlock (&test_g_static_rw_lock_lock);
+       }
+      else /* I'm a writer */
+       {
+         
+         if (g_random_double() > .2) /* I'll block */ 
+           g_static_rw_lock_writer_lock (&test_g_static_rw_lock_lock);
+         else /* I'll only try */
+           if (!g_static_rw_lock_writer_trylock (&test_g_static_rw_lock_lock))
+             continue;
+         G_LOCK (test_g_static_rw_lock_state);
+         g_assert (test_g_static_rw_lock_state == 0);
+         test_g_static_rw_lock_state = -1;
+         G_UNLOCK (test_g_static_rw_lock_state);
+
+         g_usleep (10);
+
+         G_LOCK (test_g_static_rw_lock_state);
+         test_g_static_rw_lock_state = 0;
+         G_UNLOCK (test_g_static_rw_lock_state);
+
+         g_static_rw_lock_writer_unlock (&test_g_static_rw_lock_lock);
+       }
+    }
+}
+
+static void
+test_g_static_rw_lock ()
+{
+  GThread *threads[THREADS];
+  guint i;
+  for (i = 0; i < THREADS; i++)
+    {
+      threads[i] = g_thread_create (test_g_static_rw_lock_thread, 
+                                   0, 0, TRUE, TRUE, 
+                                   G_THREAD_PRIORITY_NORMAL);      
+    }
+  g_usleep (G_MICROSEC);
+  test_g_static_rw_lock_run = FALSE;
+  for (i = 0; i < THREADS; i++)
+    {
+      g_thread_join (threads[i]);
+    }
+  g_assert (test_g_static_rw_lock_state == 0);
+}
+
+/* run all the tests */
+int 
+main (int   argc,
+      char *argv[])
+{
+  /* Only run the test, if threads are enabled and a default thread
+     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 ();
+#endif
+  return 0;
+}