+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
+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
+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
+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
+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
+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
+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
+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
gmain.c \
gmem.c \
gmessages.c \
- gmutex.c \
gnode.c \
gprimes.c \
gqueue.c \
gstack.c \
gstrfuncs.c \
gstring.c \
+ gthread.c \
gtimer.c \
gtree.c \
gutils.c
#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
#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
#undef NATIVE_WIN32
#undef G_THREAD_SOURCE
+#undef POSIX_MIN_PRIORITY
+#undef POSIX_MAX_PRIORITY
+#undef POSIX_YIELD_FUNC
#undef GLIB_NATIVE_BEOS
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
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
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
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)
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"
;;
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"
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
,
)
#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"
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
/* Timer
*/
+
+#define G_MICROSEC 1000000
+
GTimer* g_timer_new (void);
void g_timer_destroy (GTimer *timer);
void g_timer_start (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.
const gchar *format,
GDate *date);
-
/* GRelation
*
* Indexed Relations. Imagine a really simple table in a
/* 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;
(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
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;
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,
gmain.c \
gmem.c \
gmessages.c \
- gmutex.c \
gnode.c \
gprimes.c \
gqueue.c \
gstack.c \
gstrfuncs.c \
gstring.c \
+ gthread.c \
gtimer.c \
gtree.c \
gutils.c
/* Timer
*/
+
+#define G_MICROSEC 1000000
+
GTimer* g_timer_new (void);
void g_timer_destroy (GTimer *timer);
void g_timer_start (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.
const gchar *format,
GDate *date);
-
/* GRelation
*
* Indexed Relations. Imagine a really simple table in a
/* 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;
(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
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;
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,
--- /dev/null
+/* 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);
+
+}
+
if (rtimer->start.tv_usec > rtimer->end.tv_usec)
{
- rtimer->end.tv_usec += 1000000;
+ rtimer->end.tv_usec += G_MICROSEC;
rtimer->end.tv_sec--;
}
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);
+}
+
*/
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)
+++ /dev/null
-/* 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.");
-}
--- /dev/null
+/* 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);
+
+}
+
+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
EXTRA_DIST = \
gthread-posix.c \
gthread-solaris.c \
- gthread-nspr.c \
gthread-none.c \
gthread.def
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
#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
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.
*/
* 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;
}
+++ /dev/null
-/* 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 (¤t_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 (¤t_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
-};
#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)
{
{
if (!private_key)
return;
-
pthread_setspecific (*(pthread_key_t *) private_key, value);
}
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,
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
};
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)
{
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,
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
};
+++ /dev/null
-#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 (¤t_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, ¤t_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;
-}
if (rtimer->start.tv_usec > rtimer->end.tv_usec)
{
- rtimer->end.tv_usec += 1000000;
+ rtimer->end.tv_usec += G_MICROSEC;
rtimer->end.tv_sec--;
}
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);
+}
+
*/
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)
string-test \
strfunc-test \
tree-test \
- type-test
+ type-test \
+ thread-test
noinst_PROGRAMS = $(TESTS)
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
--- /dev/null
+#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;
+}