mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-04 10:16:17 +01:00
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:
parent
ed49525102
commit
90f6cc9bf2
23
ChangeLog
23
ChangeLog
@ -1,3 +1,26 @@
|
||||
1999-06-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
|
||||
|
||||
* configure.in, acglib.m4, acconfig.h, glib.h, gthread.c:
|
||||
Completed the thread support in GLib. Thread creation,
|
||||
prioritizing threads, yielding, joining threads as well as
|
||||
reader/writer locks and recursive mutexes are now in place. Please
|
||||
test heavily on your platform. It is so far tested on
|
||||
Linux/i386/pthreads, Solaris/Sparc/pthreads and
|
||||
Solaris/Sparc/solaristhreads.
|
||||
|
||||
* gtimer.c, glib.h: Implement g_usleep (gulong microseconds) for
|
||||
thread safe sleeping. (sleep() is not MT-safe at all!)
|
||||
|
||||
* gutils.c: Avoid compiler warning.
|
||||
|
||||
* tests/Makefile.am, tests/thread-test.c: New program to test some
|
||||
aspects of the thread implementation.
|
||||
|
||||
* gthread.c, Makefile.am: Renamed from gmutex.c to reflect the
|
||||
change of content.
|
||||
|
||||
* configure.in: Purged all appearances of nspr.
|
||||
|
||||
Wed Jun 2 11:42:46 PDT 1999 Manish Singh <yosh@gimp.org>
|
||||
|
||||
* acinclude.m4
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
118
configure.in
118
configure.in
@ -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
134
glib.h
@ -1500,6 +1500,9 @@ void g_blow_chunks (void);
|
||||
|
||||
/* Timer
|
||||
*/
|
||||
|
||||
#define G_MICROSEC 1000000
|
||||
|
||||
GTimer* g_timer_new (void);
|
||||
void g_timer_destroy (GTimer *timer);
|
||||
void g_timer_start (GTimer *timer);
|
||||
@ -1507,7 +1510,7 @@ void g_timer_stop (GTimer *timer);
|
||||
void g_timer_reset (GTimer *timer);
|
||||
gdouble g_timer_elapsed (GTimer *timer,
|
||||
gulong *microseconds);
|
||||
|
||||
void g_usleep (gulong microseconds);
|
||||
|
||||
/* String utility functions that modify a string argument or
|
||||
* return a constant string that must not be freed.
|
||||
@ -2367,7 +2370,6 @@ gsize g_date_strftime (gchar *s,
|
||||
const gchar *format,
|
||||
GDate *date);
|
||||
|
||||
|
||||
/* GRelation
|
||||
*
|
||||
* Indexed Relations. Imagine a really simple table in a
|
||||
@ -2819,31 +2821,63 @@ gint gwin_closedir (DIR *dir);
|
||||
|
||||
/* GLib Thread support
|
||||
*/
|
||||
|
||||
typedef void (*GThreadFunc) (gpointer value);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_THREAD_PRIORITY_LOW,
|
||||
G_THREAD_PRIORITY_NORMAL,
|
||||
G_THREAD_PRIORITY_HIGH,
|
||||
G_THREAD_PRIORITY_URGENT,
|
||||
} GThreadPriority;
|
||||
|
||||
typedef struct _GThread GThread;
|
||||
struct _GThread
|
||||
{
|
||||
GThreadPriority priority;
|
||||
gboolean bound;
|
||||
gboolean joinable;
|
||||
};
|
||||
|
||||
typedef struct _GMutex GMutex;
|
||||
typedef struct _GCond GCond;
|
||||
typedef struct _GPrivate GPrivate;
|
||||
typedef struct _GStaticPrivate GStaticPrivate;
|
||||
|
||||
typedef struct _GThreadFunctions GThreadFunctions;
|
||||
struct _GThreadFunctions
|
||||
{
|
||||
GMutex* (*mutex_new) (void);
|
||||
void (*mutex_lock) (GMutex *mutex);
|
||||
gboolean (*mutex_trylock) (GMutex *mutex);
|
||||
void (*mutex_unlock) (GMutex *mutex);
|
||||
void (*mutex_free) (GMutex *mutex);
|
||||
GCond* (*cond_new) (void);
|
||||
void (*cond_signal) (GCond *cond);
|
||||
void (*cond_broadcast) (GCond *cond);
|
||||
void (*cond_wait) (GCond *cond,
|
||||
GMutex *mutex);
|
||||
gboolean (*cond_timed_wait) (GCond *cond,
|
||||
GMutex *mutex,
|
||||
GTimeVal *end_time);
|
||||
void (*cond_free) (GCond *cond);
|
||||
GPrivate* (*private_new) (GDestroyNotify destructor);
|
||||
gpointer (*private_get) (GPrivate *private_key);
|
||||
void (*private_set) (GPrivate *private_key,
|
||||
gpointer data);
|
||||
GMutex* (*mutex_new) (void);
|
||||
void (*mutex_lock) (GMutex *mutex);
|
||||
gboolean (*mutex_trylock) (GMutex *mutex);
|
||||
void (*mutex_unlock) (GMutex *mutex);
|
||||
void (*mutex_free) (GMutex *mutex);
|
||||
GCond* (*cond_new) (void);
|
||||
void (*cond_signal) (GCond *cond);
|
||||
void (*cond_broadcast) (GCond *cond);
|
||||
void (*cond_wait) (GCond *cond,
|
||||
GMutex *mutex);
|
||||
gboolean (*cond_timed_wait) (GCond *cond,
|
||||
GMutex *mutex,
|
||||
GTimeVal *end_time);
|
||||
void (*cond_free) (GCond *cond);
|
||||
GPrivate* (*private_new) (GDestroyNotify destructor);
|
||||
gpointer (*private_get) (GPrivate *private_key);
|
||||
void (*private_set) (GPrivate *private_key,
|
||||
gpointer data);
|
||||
gpointer (*thread_create) (GThreadFunc thread_func,
|
||||
gpointer arg,
|
||||
gulong stack_size,
|
||||
gboolean joinable,
|
||||
gboolean bound,
|
||||
GThreadPriority priority);
|
||||
void (*thread_yield) (void);
|
||||
void (*thread_join) (gpointer thread);
|
||||
void (*thread_exit) (void);
|
||||
void (*thread_set_priority)(gpointer thread,
|
||||
GThreadPriority priority);
|
||||
gpointer (*thread_self) (void);
|
||||
};
|
||||
|
||||
GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
|
||||
@ -2891,6 +2925,20 @@ GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
|
||||
(void) (private_key = \
|
||||
(GPrivate*) (value)), \
|
||||
(private_key, value))
|
||||
#define g_thread_yield() G_THREAD_CF (thread_yield, (void)0, ())
|
||||
#define g_thread_exit() G_THREAD_CF (thread_exit, (void)0, ())
|
||||
|
||||
GThread* g_thread_create (GThreadFunc thread_func,
|
||||
gpointer arg,
|
||||
gulong stack_size,
|
||||
gboolean joinable,
|
||||
gboolean bound,
|
||||
GThreadPriority priority);
|
||||
GThread* g_thread_self ();
|
||||
void g_thread_join (GThread* thread);
|
||||
void g_thread_set_priority (GThread* thread,
|
||||
GThreadPriority priority);
|
||||
|
||||
/* GStaticMutexes can be statically initialized with the value
|
||||
* G_STATIC_MUTEX_INIT, and then they can directly be used, that is
|
||||
* much easier, than having to explicitly allocate the mutex before
|
||||
@ -2902,6 +2950,7 @@ GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
|
||||
g_mutex_trylock (g_static_mutex_get_mutex (mutex))
|
||||
#define g_static_mutex_unlock(mutex) \
|
||||
g_mutex_unlock (g_static_mutex_get_mutex (mutex))
|
||||
|
||||
struct _GStaticPrivate
|
||||
{
|
||||
guint index;
|
||||
@ -2911,6 +2960,51 @@ gpointer g_static_private_get (GStaticPrivate *private_key);
|
||||
void g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
gpointer g_static_private_get_for_thread (GStaticPrivate *private_key,
|
||||
GThread *thread);
|
||||
void g_static_private_set_for_thread (GStaticPrivate *private_key,
|
||||
GThread *thread,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
#ifndef G_STATIC_REC_MUTEX_INIT
|
||||
/* if GStaticRecMutex is not just a differently initialized GStaticMutex,
|
||||
* the following is done:
|
||||
* This can't be done in glibconfig.h, as GStaticPrivate and gboolean
|
||||
* are not yet known there
|
||||
*/
|
||||
typedef struct _GStaticRecMutex GStaticRecMutex;
|
||||
struct _GStaticRecMutex
|
||||
{
|
||||
GStaticMutex mutex;
|
||||
GStaticPrivate counter;
|
||||
};
|
||||
#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT, G_STATIC_PRIVATE_INIT }
|
||||
void g_static_rec_mutex_lock (GStaticRecMutex* mutex);
|
||||
gboolean g_static_rec_mutex_trylock (GStaticRecMutex* mutex);
|
||||
void g_static_rec_mutex_unlock (GStaticRecMutex* mutex);
|
||||
#define g_static_rec_mutex_get_mutex(mutex) ((mutex)->mutex)
|
||||
#endif /* G_STATIC_REC_MUTEX_INIT */
|
||||
|
||||
typedef struct _GStaticRWLock GStaticRWLock;
|
||||
struct _GStaticRWLock
|
||||
{
|
||||
GStaticMutex mutex;
|
||||
GCond *read_cond;
|
||||
GCond *write_cond;
|
||||
guint read_counter;
|
||||
gboolean write;
|
||||
guint want_to_write;
|
||||
};
|
||||
|
||||
#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE }
|
||||
|
||||
void g_static_rw_lock_reader_lock (GStaticRWLock* lock);
|
||||
gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_reader_unlock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_writer_lock (GStaticRWLock* lock);
|
||||
gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_free (GStaticRWLock* lock);
|
||||
|
||||
/* these are some convenience macros that expand to nothing if GLib
|
||||
* was configured with --disable-threads. for using StaticMutexes,
|
||||
|
@ -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
|
||||
|
134
glib/glib.h
134
glib/glib.h
@ -1500,6 +1500,9 @@ void g_blow_chunks (void);
|
||||
|
||||
/* Timer
|
||||
*/
|
||||
|
||||
#define G_MICROSEC 1000000
|
||||
|
||||
GTimer* g_timer_new (void);
|
||||
void g_timer_destroy (GTimer *timer);
|
||||
void g_timer_start (GTimer *timer);
|
||||
@ -1507,7 +1510,7 @@ void g_timer_stop (GTimer *timer);
|
||||
void g_timer_reset (GTimer *timer);
|
||||
gdouble g_timer_elapsed (GTimer *timer,
|
||||
gulong *microseconds);
|
||||
|
||||
void g_usleep (gulong microseconds);
|
||||
|
||||
/* String utility functions that modify a string argument or
|
||||
* return a constant string that must not be freed.
|
||||
@ -2367,7 +2370,6 @@ gsize g_date_strftime (gchar *s,
|
||||
const gchar *format,
|
||||
GDate *date);
|
||||
|
||||
|
||||
/* GRelation
|
||||
*
|
||||
* Indexed Relations. Imagine a really simple table in a
|
||||
@ -2819,31 +2821,63 @@ gint gwin_closedir (DIR *dir);
|
||||
|
||||
/* GLib Thread support
|
||||
*/
|
||||
|
||||
typedef void (*GThreadFunc) (gpointer value);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
G_THREAD_PRIORITY_LOW,
|
||||
G_THREAD_PRIORITY_NORMAL,
|
||||
G_THREAD_PRIORITY_HIGH,
|
||||
G_THREAD_PRIORITY_URGENT,
|
||||
} GThreadPriority;
|
||||
|
||||
typedef struct _GThread GThread;
|
||||
struct _GThread
|
||||
{
|
||||
GThreadPriority priority;
|
||||
gboolean bound;
|
||||
gboolean joinable;
|
||||
};
|
||||
|
||||
typedef struct _GMutex GMutex;
|
||||
typedef struct _GCond GCond;
|
||||
typedef struct _GPrivate GPrivate;
|
||||
typedef struct _GStaticPrivate GStaticPrivate;
|
||||
|
||||
typedef struct _GThreadFunctions GThreadFunctions;
|
||||
struct _GThreadFunctions
|
||||
{
|
||||
GMutex* (*mutex_new) (void);
|
||||
void (*mutex_lock) (GMutex *mutex);
|
||||
gboolean (*mutex_trylock) (GMutex *mutex);
|
||||
void (*mutex_unlock) (GMutex *mutex);
|
||||
void (*mutex_free) (GMutex *mutex);
|
||||
GCond* (*cond_new) (void);
|
||||
void (*cond_signal) (GCond *cond);
|
||||
void (*cond_broadcast) (GCond *cond);
|
||||
void (*cond_wait) (GCond *cond,
|
||||
GMutex *mutex);
|
||||
gboolean (*cond_timed_wait) (GCond *cond,
|
||||
GMutex *mutex,
|
||||
GTimeVal *end_time);
|
||||
void (*cond_free) (GCond *cond);
|
||||
GPrivate* (*private_new) (GDestroyNotify destructor);
|
||||
gpointer (*private_get) (GPrivate *private_key);
|
||||
void (*private_set) (GPrivate *private_key,
|
||||
gpointer data);
|
||||
GMutex* (*mutex_new) (void);
|
||||
void (*mutex_lock) (GMutex *mutex);
|
||||
gboolean (*mutex_trylock) (GMutex *mutex);
|
||||
void (*mutex_unlock) (GMutex *mutex);
|
||||
void (*mutex_free) (GMutex *mutex);
|
||||
GCond* (*cond_new) (void);
|
||||
void (*cond_signal) (GCond *cond);
|
||||
void (*cond_broadcast) (GCond *cond);
|
||||
void (*cond_wait) (GCond *cond,
|
||||
GMutex *mutex);
|
||||
gboolean (*cond_timed_wait) (GCond *cond,
|
||||
GMutex *mutex,
|
||||
GTimeVal *end_time);
|
||||
void (*cond_free) (GCond *cond);
|
||||
GPrivate* (*private_new) (GDestroyNotify destructor);
|
||||
gpointer (*private_get) (GPrivate *private_key);
|
||||
void (*private_set) (GPrivate *private_key,
|
||||
gpointer data);
|
||||
gpointer (*thread_create) (GThreadFunc thread_func,
|
||||
gpointer arg,
|
||||
gulong stack_size,
|
||||
gboolean joinable,
|
||||
gboolean bound,
|
||||
GThreadPriority priority);
|
||||
void (*thread_yield) (void);
|
||||
void (*thread_join) (gpointer thread);
|
||||
void (*thread_exit) (void);
|
||||
void (*thread_set_priority)(gpointer thread,
|
||||
GThreadPriority priority);
|
||||
gpointer (*thread_self) (void);
|
||||
};
|
||||
|
||||
GUTILS_C_VAR GThreadFunctions g_thread_functions_for_glib_use;
|
||||
@ -2891,6 +2925,20 @@ GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
|
||||
(void) (private_key = \
|
||||
(GPrivate*) (value)), \
|
||||
(private_key, value))
|
||||
#define g_thread_yield() G_THREAD_CF (thread_yield, (void)0, ())
|
||||
#define g_thread_exit() G_THREAD_CF (thread_exit, (void)0, ())
|
||||
|
||||
GThread* g_thread_create (GThreadFunc thread_func,
|
||||
gpointer arg,
|
||||
gulong stack_size,
|
||||
gboolean joinable,
|
||||
gboolean bound,
|
||||
GThreadPriority priority);
|
||||
GThread* g_thread_self ();
|
||||
void g_thread_join (GThread* thread);
|
||||
void g_thread_set_priority (GThread* thread,
|
||||
GThreadPriority priority);
|
||||
|
||||
/* GStaticMutexes can be statically initialized with the value
|
||||
* G_STATIC_MUTEX_INIT, and then they can directly be used, that is
|
||||
* much easier, than having to explicitly allocate the mutex before
|
||||
@ -2902,6 +2950,7 @@ GMutex* g_static_mutex_get_mutex_impl (GMutex **mutex);
|
||||
g_mutex_trylock (g_static_mutex_get_mutex (mutex))
|
||||
#define g_static_mutex_unlock(mutex) \
|
||||
g_mutex_unlock (g_static_mutex_get_mutex (mutex))
|
||||
|
||||
struct _GStaticPrivate
|
||||
{
|
||||
guint index;
|
||||
@ -2911,6 +2960,51 @@ gpointer g_static_private_get (GStaticPrivate *private_key);
|
||||
void g_static_private_set (GStaticPrivate *private_key,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
gpointer g_static_private_get_for_thread (GStaticPrivate *private_key,
|
||||
GThread *thread);
|
||||
void g_static_private_set_for_thread (GStaticPrivate *private_key,
|
||||
GThread *thread,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
#ifndef G_STATIC_REC_MUTEX_INIT
|
||||
/* if GStaticRecMutex is not just a differently initialized GStaticMutex,
|
||||
* the following is done:
|
||||
* This can't be done in glibconfig.h, as GStaticPrivate and gboolean
|
||||
* are not yet known there
|
||||
*/
|
||||
typedef struct _GStaticRecMutex GStaticRecMutex;
|
||||
struct _GStaticRecMutex
|
||||
{
|
||||
GStaticMutex mutex;
|
||||
GStaticPrivate counter;
|
||||
};
|
||||
#define G_STATIC_REC_MUTEX_INIT { G_STATIC_MUTEX_INIT, G_STATIC_PRIVATE_INIT }
|
||||
void g_static_rec_mutex_lock (GStaticRecMutex* mutex);
|
||||
gboolean g_static_rec_mutex_trylock (GStaticRecMutex* mutex);
|
||||
void g_static_rec_mutex_unlock (GStaticRecMutex* mutex);
|
||||
#define g_static_rec_mutex_get_mutex(mutex) ((mutex)->mutex)
|
||||
#endif /* G_STATIC_REC_MUTEX_INIT */
|
||||
|
||||
typedef struct _GStaticRWLock GStaticRWLock;
|
||||
struct _GStaticRWLock
|
||||
{
|
||||
GStaticMutex mutex;
|
||||
GCond *read_cond;
|
||||
GCond *write_cond;
|
||||
guint read_counter;
|
||||
gboolean write;
|
||||
guint want_to_write;
|
||||
};
|
||||
|
||||
#define G_STATIC_RW_LOCK_INIT { G_STATIC_MUTEX_INIT, NULL, NULL, 0, FALSE, FALSE }
|
||||
|
||||
void g_static_rw_lock_reader_lock (GStaticRWLock* lock);
|
||||
gboolean g_static_rw_lock_reader_trylock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_reader_unlock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_writer_lock (GStaticRWLock* lock);
|
||||
gboolean g_static_rw_lock_writer_trylock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_writer_unlock (GStaticRWLock* lock);
|
||||
void g_static_rw_lock_free (GStaticRWLock* lock);
|
||||
|
||||
/* these are some convenience macros that expand to nothing if GLib
|
||||
* was configured with --disable-threads. for using StaticMutexes,
|
||||
|
535
glib/gthread.c
Normal file
535
glib/gthread.c
Normal 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);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
202
gmutex.c
@ -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
535
gthread.c
Normal 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);
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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 (¤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
|
||||
};
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 (¤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;
|
||||
}
|
12
gtimer.c
12
gtimer.c
@ -176,7 +176,7 @@ g_timer_elapsed (GTimer *timer,
|
||||
|
||||
if (rtimer->start.tv_usec > rtimer->end.tv_usec)
|
||||
{
|
||||
rtimer->end.tv_usec += 1000000;
|
||||
rtimer->end.tv_usec += G_MICROSEC;
|
||||
rtimer->end.tv_sec--;
|
||||
}
|
||||
|
||||
@ -191,3 +191,13 @@ g_timer_elapsed (GTimer *timer,
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void
|
||||
g_usleep (gulong microseconds)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = microseconds / G_MICROSEC;
|
||||
tv.tv_usec = microseconds % G_MICROSEC;
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
|
||||
|
4
gutils.c
4
gutils.c
@ -478,8 +478,8 @@ g_get_any_init (void)
|
||||
*/
|
||||
if (error == 0 || error == ENOENT)
|
||||
{
|
||||
g_warning ("getpwuid_r(): failed due to: No such user %d.",
|
||||
getuid ());
|
||||
g_warning ("getpwuid_r(): failed due to: "
|
||||
"No such user: %lu.", (unsigned long)getuid ());
|
||||
break;
|
||||
}
|
||||
if (bufsize > 32 * 1024)
|
||||
|
@ -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
238
tests/thread-test.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user