Completed the thread support in GLib. Thread creation, prioritizing

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.
This commit is contained in:
Sebastian Wilhelmi 1999-06-17 15:39:31 +00:00 committed by Sebastian Wilhelmi
parent ed49525102
commit 90f6cc9bf2
31 changed files with 2095 additions and 716 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -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

View 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
,
)
@ -1052,6 +1121,32 @@ $g_enable_threads_def G_THREADS_ENABLED
typedef struct _GMutex* GStaticMutex;
#define G_STATIC_MUTEX_INIT NULL
#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
@ -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

134
glib.h
View 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,

View 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

View 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,

535
glib/gthread.c Normal file
View File

@ -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);
}

View 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);
}

View 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)

202
gmutex.c
View File

@ -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.");
}

535
gthread.c Normal file
View File

@ -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);
}

View 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

View 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

View 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;
}

View File

@ -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
};

View File

@ -38,6 +38,19 @@
#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, \
@ -54,12 +67,24 @@
# 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
};

View File

@ -46,6 +46,14 @@
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
};

View File

@ -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;
}

View 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);
}

View 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)

View 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

238
tests/thread-test.c Normal file
View File

@ -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;
}