diff --git a/lib/glcond.h b/lib/glcond.h
new file mode 100644
index 0000000..05af610
--- /dev/null
+++ b/lib/glcond.h
@@ -0,0 +1,325 @@
+/* Condition waiting in multithreaded situations.
+ Copyright (C) 2005-2008 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Yoann Vandoorselaere
, 2008.
+ Based on Bruno Haible lock.h */
+
+/*
+ Condition variables can be used for waiting until a condition
+ becomes true. In this respect, they are similar to wait queues. But
+ contrary to wait queues, condition variables have different
+ semantics that allows events to be lost when there is no thread
+ waiting for them.
+
+ Condition variable:
+ Type: gl_cond_t
+ Declaration: gl_cond_define(extern, name)
+ Initializer: gl_cond_define_initialized(, name)
+ Waiting: gl_cond_wait(name)
+ Timed wait: gl_cond_timedwait(name, tv)
+ Signaling: gl_cond_signal(name)
+ Broadcasting: gl_cond_broadcast(name)
+*/
+
+
+#ifndef _GLCOND_H
+#define _GLCOND_H
+
+#include
+#include "lock.h"
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+/* Use the POSIX threads library. */
+
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The pthread_in_use() detection needs to be done at runtime. */
+# define pthread_in_use() \
+ glthread_in_use ()
+extern int glthread_in_use (void);
+
+# endif
+
+# if USE_POSIX_THREADS_WEAK
+
+/* Use weak references to the POSIX threads library. */
+
+/* Weak references avoid dragging in external libraries if the other parts
+ of the program don't use them. Here we use them, because we don't want
+ every program that uses libintl to depend on libpthread. This assumes
+ that libpthread would not be loaded after libintl; i.e. if libintl is
+ loaded first, by an executable that does not depend on libpthread, and
+ then a module is dynamically loaded that depends on libpthread, libintl
+ will not be multithread-safe. */
+
+/* The way to test at runtime whether libpthread is present is to test
+ whether a function pointer's value, such as &pthread_mutex_init, is
+ non-NULL. However, some versions of GCC have a bug through which, in
+ PIC mode, &foo != NULL always evaluates to true if there is a direct
+ call to foo(...) in the same function. To avoid this, we test the
+ address of a function in libpthread that we don't use. */
+
+# pragma weak pthread_cond_init
+# pragma weak pthread_cond_wait
+# pragma weak pthread_cond_timedwait
+# pragma weak pthread_cond_signal
+# pragma weak pthread_cond_broadcast
+# pragma weak pthread_cond_destroy
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# pragma weak pthread_cancel
+# define pthread_in_use() (pthread_cancel != NULL)
+# endif
+
+# else
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# define pthread_in_use() 1
+# endif
+
+# endif
+
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+typedef pthread_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pthread_cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ PTHREAD_COND_INITIALIZER
+# define glthread_cond_init(COND) \
+ (pthread_in_use () ? pthread_cond_init (COND, NULL) : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pthread_in_use () ? pthread_cond_wait (COND, LOCK) : 0)
+# define glthread_cond_timedwait(COND, LOCK, TS) \
+ (pthread_in_use () ? pthread_cond_timedwait (COND, LOCK, TS) : 0)
+# define glthread_cond_signal(COND) \
+ (pthread_in_use () ? pthread_cond_signal (COND) : 0)
+# define glthread_cond_broadcast(COND) \
+ (pthread_in_use () ? pthread_cond_broadcast (COND) : 0)
+# define glthread_cond_destroy(COND) \
+ (pthread_in_use () ? pthread_cond_destroy (COND) : 0)
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_PTH_THREADS
+
+/* Use the GNU Pth threads library. */
+
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_PTH_THREADS_WEAK
+
+/* Use weak references to the GNU Pth threads library. */
+
+# pragma weak pth_cond_init
+# pragma weak pth_cond_await
+# pragma weak pth_cond_notify
+# pragma weak pth_event
+# pragma weak pth_timeout
+# pragma weak pth_cancel
+# define pth_in_use() (pth_cancel != NULL)
+
+# else
+
+# define pth_in_use() 1
+
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+typedef pth_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS pth_cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS pth_cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ PTH_COND_INIT
+# define glthread_cond_init(COND) \
+ (pth_in_use () && !pth_cond_init (COND) ? errno : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pth_in_use () && !pth_cond_await (COND, LOCK, NULL) ? errno : 0)
+
+static inline int
+glthread_cond_timedwait (gl_cond_t * cond,
+ gl_lock_t * lock,
+ struct timespec *ts)
+{
+ int ret, status;
+ pth_event_t ev;
+
+ if (!pth_in_use ())
+ return 0;
+
+ ev = pth_event (PTH_EVENT_TIME, pth_time (ts->tv_sec, ts->tv_nsec / 1000));
+ ret = pth_cond_await (cond, lock, ev);
+
+ status = pth_event_status (ev);
+ pth_event_free (ev, PTH_FREE_THIS);
+
+ if (status == PTH_STATUS_OCCURRED)
+ return ETIMEDOUT;
+
+ return ret;
+}
+
+# define glthread_cond_signal(COND) \
+ (pth_in_use () && !pth_cond_notify (COND, FALSE) ? errno : 0)
+# define glthread_cond_broadcast(COND) \
+ (pth_in_use () && !pth_cond_notify (COND, TRUE) ? errno : 0)
+# define glthread_cond_destroy(COND) 0
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_SOLARIS_THREADS
+
+/* Use the old Solaris threads library. */
+
+# include
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_SOLARIS_THREADS_WEAK
+
+/* Use weak references to the old Solaris threads library. */
+
+# pragma weak cond_init
+# pragma weak cond_wait
+# pragma weak cond_timedwait
+# pragma weak cond_signal
+# pragma weak cond_broadcast
+# pragma weak cond_destroy
+# pragma weak thr_suspend
+# define thread_in_use() (thr_suspend != NULL)
+
+# else
+
+# define thread_in_use() 1
+
+# endif
+
+/* -------------------------- gl_cond_t datatype -------------------------- */
+
+#define ETIMEDOUT ETIME
+
+typedef pthread_cond_t gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME) \
+ STORAGECLASS cond_t NAME;
+# define gl_cond_define_initialized(STORAGECLASS, NAME) \
+ STORAGECLASS cond_t NAME = gl_cond_initializer;
+# define gl_cond_initializer \
+ DEFAULTCV
+# define glthread_cond_init(COND) \
+ (pthread_in_use () ? cond_init (COND, USYNC_THREAD, NULL) : 0)
+# define glthread_cond_wait(COND, LOCK) \
+ (pthread_in_use () ? cond_wait (COND, LOCK) : 0)
+# define glthread_cond_timedwait(COND, LOCK, TS) \
+ (pthread_in_use () ? cond_timedwait (COND, LOCK, TS) : 0)
+# define glthread_cond_signal(COND) \
+ (pthread_in_use () ? cond_signal (COND) : 0)
+# define glthread_cond_broadcast(COND) \
+ (pthread_in_use () ? cond_broadcast (COND) : 0)
+# define glthread_cond_destroy(COND) \
+ (pthread_in_use () ? cond_destroy (COND) : 0)
+
+#endif
+
+/* ========================================================================= */
+
+#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
+
+/* Provide dummy implementation if threads are not supported. */
+
+typedef int gl_cond_t;
+# define gl_cond_define(STORAGECLASS, NAME)
+# define gl_cond_define_initialized(STORAGECLASS, NAME)
+# define glthread_cond_init(COND) 0
+# define glthread_cond_signal(COND) 0
+# define glthread_cond_broadcast(COND) 0
+# define glthread_cond_wait(COND, LOCK) 0
+# define glthread_cond_timedwait(COND, LOCK, TS) 0
+# define glthread_cond_destroy(COND) 0
+
+#endif
+
+
+/* ========================================================================= */
+
+/* Macros with built-in error handling. */
+
+#define gl_cond_init(COND) \
+ do \
+ { \
+ if (glthread_cond_init (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_wait(COND, LOCK) \
+ do \
+ { \
+ if (glthread_cond_wait (&COND, &LOCK)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_signal(COND) \
+ do \
+ { \
+ if (glthread_cond_signal (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_broadcast(COND) \
+ do \
+ { \
+ if (glthread_cond_broadcast (&COND)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_cond_destroy(COND) \
+ do \
+ { \
+ if (glthread_cond_destroy (&COND)) \
+ abort (); \
+ } \
+ while (0)
+
+#endif /* _GLCOND_H */
diff --git a/lib/glthread.h b/lib/glthread.h
new file mode 100644
index 0000000..9316b77
--- /dev/null
+++ b/lib/glthread.h
@@ -0,0 +1,277 @@
+/* Locking in multithreaded situations.
+ Copyright (C) 2005-2008 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Bruno Haible , 2005.
+ Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-solaris.h,
+ gthr-win32.h. */
+
+/* This file contains locking primitives for use with a given thread library.
+ It does not contain primitives for creating threads or for other
+ synchronization primitives.
+*/
+
+
+#ifndef _GLTHREAD_H
+#define _GLTHREAD_H
+
+#include
+
+/* ========================================================================= */
+
+#if USE_POSIX_THREADS
+
+/* Use the POSIX threads library. */
+
+# include
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if PTHREAD_IN_USE_DETECTION_HARD
+
+/* The pthread_in_use() detection needs to be done at runtime. */
+# define pthread_in_use() \
+ glthread_in_use ()
+extern int glthread_in_use (void);
+
+# endif
+
+# if USE_POSIX_THREADS_WEAK
+
+/* Use weak references to the POSIX threads library. */
+
+/* Weak references avoid dragging in external libraries if the other parts
+ of the program don't use them. Here we use them, because we don't want
+ every program that uses libintl to depend on libpthread. This assumes
+ that libpthread would not be loaded after libintl; i.e. if libintl is
+ loaded first, by an executable that does not depend on libpthread, and
+ then a module is dynamically loaded that depends on libpthread, libintl
+ will not be multithread-safe. */
+
+/* The way to test at runtime whether libpthread is present is to test
+ whether a function pointer's value, such as &pthread_mutex_init, is
+ non-NULL. However, some versions of GCC have a bug through which, in
+ PIC mode, &foo != NULL always evaluates to true if there is a direct
+ call to foo(...) in the same function. To avoid this, we test the
+ address of a function in libpthread that we don't use. */
+
+# pragma weak pthread_create
+# pragma weak pthread_join
+# pragma weak pthread_self
+# pragma weak pthread_exit
+# pragma weak pthread_sigmask
+
+# ifdef HAVE_PTHREAD_ATFORK
+# pragma weak pthread_atfork
+# endif
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# pragma weak pthread_cancel
+# define pthread_in_use() (pthread_cancel != NULL)
+# endif
+
+# else
+
+# if !PTHREAD_IN_USE_DETECTION_HARD
+# define pthread_in_use() 1
+# endif
+
+# endif
+
+
+/* -------------------------- gl_thread_t datatype -------------------------- */
+
+typedef pthread_t gl_thread_t;
+# define glthread_create(THREAD, FUNC, ARG) \
+ (pthread_in_use () ? pthread_create (THREAD, NULL, FUNC, ARG) : 0)
+# define glthread_sigmask(HOW, SET, OSET) \
+ (pthread_in_use () ? pthread_sigmask (HOW, SET, OSET) : 0)
+# define glthread_join(THREAD, VALPTR) \
+ (pthread_in_use () ? pthread_join (THREAD, VALPTR) : 0)
+# define glthread_self() \
+ (pthread_in_use () ? (void *) pthread_self () : 0)
+# define glthread_exit(VALPTR) \
+ (pthread_in_use () ? pthread_exit (VALPTR) : 0)
+
+# ifdef HAVE_PTHREAD_ATFORK
+# define glthread_atfork(PREPARE, PARENT, CHILD) \
+ (pthread_in_use () ? pthread_atfork (PREPARE, PARENT, CHILD) : 0)
+# else
+# define glthread_atfork(PREPARE, PARENT, CHILD) 0
+# endif
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_PTH_THREADS
+
+/* Use the GNU Pth threads library. */
+
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_PTH_THREADS_WEAK
+
+/* Use weak references to the GNU Pth threads library. */
+
+# pragma weak pth_spawn
+# pragma weak pth_sigmask
+# pragma weak pth_join
+# pragma weak pth_self
+# pragma weak pth_exit
+# pragma weak pth_cancel
+# define pth_in_use() (pth_cancel != NULL)
+
+# else
+
+# define pth_in_use() 1
+
+# endif
+/* -------------------------- gl_thread_t datatype -------------------------- */
+
+typedef pth_t gl_thread_t;
+# define glthread_create(THREAD, FUNC, ARG) \
+ (pth_in_use () ? ((*(THREAD) = pth_spawn (NULL, FUNC, ARG)) ? 0 : -1) : 0)
+# define glthread_sigmask(HOW, SET, OSET) \
+ (pth_in_use && !pth_sigmask (HOW, SET, OSET) ? errno : 0)
+# define glthread_join(THREAD, VALPTR) \
+ (pth_in_use () && !pth_join (THREAD, VALPTR) ? errno : 0)
+# define glthread_self() \
+ (pth_in_use () ? (void *) pth_self () : 0)
+# define glthread_exit(VALPTR) \
+ (pth_in_use () ? pth_exit (VALPTR) : 0)
+# define glthread_atfork(PREPARE, PARENT, CHILD) 0
+
+#endif
+
+/* ========================================================================= */
+
+#if USE_SOLARIS_THREADS
+
+/* Use the old Solaris threads library. */
+
+# include
+# include
+# include
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# if USE_SOLARIS_THREADS_WEAK
+
+/* Use weak references to the old Solaris threads library. */
+
+# pragma weak thr_create
+# pragma weak thr_join
+# pragma weak thr_self
+# pragma weak thr_exit
+# pragma weak thr_suspend
+# define thread_in_use() (thr_suspend != NULL)
+
+# else
+
+# define thread_in_use() 1
+
+# endif
+
+/* -------------------------- gl_thread_t datatype -------------------------- */
+
+typedef thread_t gl_thread_t;
+# define glthread_create(THREAD, FUNC, ARG) \
+ (thread_in_use () ? thr_create (NULL, 0, FUNC, ARG, 0, THREAD) : 0)
+# define glthread_sigmask(HOW, SET, OSET) \
+ (pthread_in_use () ? sigprocmask (HOW, SET, OSET) : 0)
+# define glthread_join(THREAD, RETVAL) \
+ (pthread_in_use () ? thr_join (THREAD, NULL, RETVAL) : 0)
+# define glthread_self() \
+ (pthread_in_use () ? (void *) thr_self () : 0)
+# define glthread_exit(VALPTR) \
+ (pthread_in_use () ? thr_exit (VALPTR) : 0)
+# define glthread_atfork(PREPARE, PARENT, CHILD) 0
+#endif
+
+
+/* ========================================================================= */
+
+#if !(USE_POSIX_THREADS || USE_PTH_THREADS || USE_SOLARIS_THREADS || USE_WIN32_THREADS)
+
+/* Provide dummy implementation if threads are not supported. */
+
+typedef int gl_thread_t;
+# define glthread_create(THREAD, FUNC, ARG) 0
+# define glthread_sigmask(HOW, SET, OSET) 0
+# define glthread_join(THREAD, RETVAL) 0
+# define glthread_self() NULL
+# define glthread_exit(VALPTR) 0
+# define glthread_atfork(PREPARE, PARENT, CHILD) 0
+
+#endif
+
+
+/* ========================================================================= */
+
+/* Macros with built-in error handling. */
+
+static inline int
+gl_thread_create_func (gl_thread_t * thread,
+ void *(*func) (void *arg),
+ void *arg)
+{
+ int ret;
+
+ ret = glthread_create (thread, func, arg);
+ if (ret)
+ abort ();
+
+ return ret;
+}
+
+#define gl_thread_create(THREAD, FUNC, ARG) \
+ gl_thread_create_func(&THREAD, FUNC, ARG)
+
+#define gl_thread_sigmask(HOW, SET, OSET) \
+ do \
+ { \
+ if (glthread_sigmask (HOW, SET, OSET)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_thread_join(THREAD, RETVAL) \
+ do \
+ { \
+ if (glthread_join (THREAD, RETVAL)) \
+ abort (); \
+ } \
+ while (0)
+#define gl_thread_atfork(PREPARE, PARENT, CHILD) \
+ do \
+ { \
+ if (glthread_atfork (PREPARE, PARENT, CHILD)) \
+ abort (); \
+ } \
+ while (0)
+
+#endif /* _GLCOND_H */
diff --git a/m4/glcond.m4 b/m4/glcond.m4
new file mode 100644
index 0000000..b98d51e
--- /dev/null
+++ b/m4/glcond.m4
@@ -0,0 +1,11 @@
+# glcond.m4 serial 1 (gettext-0.15)
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_COND],
+[
+ AC_C_INLINE()
+ AC_REQUIRE([gl_LOCK])
+])
diff --git a/m4/glthread.m4 b/m4/glthread.m4
new file mode 100644
index 0000000..43bd94d
--- /dev/null
+++ b/m4/glthread.m4
@@ -0,0 +1,15 @@
+# glcond.m4 serial 1 (gettext-0.15)
+dnl Copyright (C) 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_THREAD],
+[
+ AC_C_INLINE()
+ AC_REQUIRE([gl_LOCK])
+
+ if test $gl_threads_api = posix; then
+ AC_CHECK_FUNC(pthread_atfork)
+ fi
+])
diff --git a/modules/glcond b/modules/glcond
new file mode 100644
index 0000000..6bac3be
--- /dev/null
+++ b/modules/glcond
@@ -0,0 +1,25 @@
+Description:
+Condition in multithreaded situations.
+
+Files:
+lib/glcond.h
+m4/glcond.m4
+
+Depends-on:
+lock
+
+configure.ac:
+gl_COND
+
+Makefile.am:
+lib_SOURCES += glcond.h
+
+Include:
+"glcond.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Yoann Vandoorselaere
+
diff --git a/modules/glcond-tests b/modules/glcond-tests
new file mode 100644
index 0000000..9ff44a0
--- /dev/null
+++ b/modules/glcond-tests
@@ -0,0 +1,22 @@
+Files:
+tests/test-glcond.c
+
+Depends-on:
+glthread
+
+configure.ac:
+dnl Checks for special libraries for the tests/test-lock test.
+dnl On some systems, sched_yield is in librt, rather than in libpthread.
+LIBSCHED=
+if test $gl_threads_api = posix; then
+ dnl Solaris has sched_yield in librt, not in libpthread or libc.
+ AC_CHECK_LIB(rt, sched_yield, [LIBSCHED=-lrt],
+ [dnl Solaris 2.5.1, 2.6 has sched_yield in libposix4, not librt.
+ AC_CHECK_LIB(posix4, sched_yield, [LIBSCHED=-lposix4])])
+fi
+AC_SUBST([LIBSCHED])
+
+Makefile.am:
+TESTS += test-glcond
+check_PROGRAMS += test-glcond
+test_glcond_LDADD = $(LDADD) @LIBMULTITHREAD@ @LIBSCHED@
diff --git a/modules/glthread b/modules/glthread
new file mode 100644
index 0000000..1cc4b30
--- /dev/null
+++ b/modules/glthread
@@ -0,0 +1,22 @@
+Description:
+Locking in multithreaded situations.
+
+Files:
+lib/glthread.h
+m4/glthread.m4
+
+configure.ac:
+gl_THREAD
+
+Makefile.am:
+lib_SOURCES += glthread.h
+
+Include:
+"glthread.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+Yoann Vandoorselaere
+
diff --git a/modules/lock-tests b/modules/lock-tests
index 7c72c94..e79945d 100644
--- a/modules/lock-tests
+++ b/modules/lock-tests
@@ -2,6 +2,7 @@ Files:
tests/test-lock.c
Depends-on:
+glthread
configure.ac:
dnl Checks for special libraries for the tests/test-lock test.
diff --git a/tests/test-glcond.c b/tests/test-glcond.c
new file mode 100644
index 0000000..aaac4df
--- /dev/null
+++ b/tests/test-glcond.c
@@ -0,0 +1,269 @@
+/* Test of condition in multithreaded situations.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+#include
+
+#if USE_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS
+
+#if USE_POSIX_THREADS
+# define TEST_POSIX_THREADS 1
+#endif
+#if USE_SOLARIS_THREADS
+# define TEST_SOLARIS_THREADS 1
+#endif
+#if USE_PTH_THREADS
+# define TEST_PTH_THREADS 1
+#endif
+#if USE_WIN32_THREADS
+# define TEST_WIN32_THREADS 1
+#endif
+
+/* Whether to enable locking.
+ Uncomment this to get a test program without locking, to verify that
+ it crashes. */
+#define ENABLE_LOCKING 1
+
+/* Which tests to perform.
+ Uncomment some of these, to verify that all tests crash if no locking
+ is enabled. */
+#define DO_TEST_COND 1
+#define DO_TEST_TIMEDCOND 1
+
+
+/* Whether to help the scheduler through explicit yield().
+ Uncomment this to see if the operating system has a fair scheduler. */
+#define EXPLICIT_YIELD 1
+
+/* Whether to print debugging messages. */
+#define ENABLE_DEBUGGING 0
+
+#include
+#include
+#include
+
+#if !ENABLE_LOCKING
+# undef USE_POSIX_THREADS
+# undef USE_SOLARIS_THREADS
+# undef USE_PTH_THREADS
+# undef USE_WIN32_THREADS
+#endif
+
+#include "glthread.h"
+#include "glcond.h"
+#include "lock.h"
+
+#if ENABLE_DEBUGGING
+# define dbgprintf printf
+#else
+# define dbgprintf if (0) printf
+#endif
+
+#if TEST_POSIX_THREADS
+# include
+static inline void
+gl_thread_yield (void)
+{
+ sched_yield ();
+}
+#endif
+
+#if TEST_PTH_THREADS
+# include
+static inline void
+gl_thread_yield (void)
+{
+ pth_yield (NULL);
+}
+#endif
+
+#if TEST_SOLARIS_THREADS
+# include
+static inline void
+gl_thread_yield (void)
+{
+ thr_yield ();
+}
+#endif
+
+#if TEST_WIN32_THREADS
+static inline void
+gl_thread_yield (void)
+{
+ Sleep (0);
+}
+#endif
+
+#if EXPLICIT_YIELD
+# define yield() gl_thread_yield ()
+#else
+# define yield()
+#endif
+
+
+/*
+ * Condition check
+ */
+#include
+static int cond_value = 0;
+static gl_cond_t condtest = gl_cond_initializer;
+static gl_lock_t lockcond = gl_lock_initializer;
+
+static void *
+cond_routine (void *arg)
+{
+ gl_lock_lock (lockcond);
+ while (!cond_value)
+ {
+ gl_cond_wait (condtest, lockcond);
+ }
+ gl_lock_unlock (lockcond);
+
+ cond_value = 2;
+
+ return NULL;
+}
+
+void
+test_cond ()
+{
+ int remain = 2;
+ gl_thread_t thread;
+
+ cond_value = 0;
+
+ gl_thread_create (thread, cond_routine, NULL);
+ do
+ {
+ yield ();
+ remain = sleep (remain);
+ }
+ while (remain);
+
+ /* signal condition */
+ gl_lock_lock (lockcond);
+ cond_value = 1;
+ gl_cond_signal (condtest);
+ gl_lock_unlock (lockcond);
+
+ gl_thread_join (thread, NULL);
+
+ if (cond_value != 2)
+ abort ();
+}
+
+
+/*
+ * Timed Condition check
+ */
+static int cond_timeout;
+
+static void
+get_ts (struct timespec *ts)
+{
+ struct timeval now;
+
+ gettimeofday (&now, NULL);
+
+ ts->tv_sec = now.tv_sec + 1;
+ ts->tv_nsec = now.tv_usec * 1000;
+}
+
+static void *
+timedcond_routine (void *arg)
+{
+ int ret;
+ struct timespec ts;
+
+ gl_lock_lock (lockcond);
+ while (!cond_value)
+ {
+ get_ts (&ts);
+ ret = glthread_cond_timedwait (&condtest, &lockcond, &ts);
+ if (ret == ETIMEDOUT)
+ cond_timeout = 1;
+ }
+ gl_lock_unlock (lockcond);
+
+ return NULL;
+}
+
+static void
+test_timedcond (void)
+{
+ int remain = 2;
+ gl_thread_t thread;
+
+ cond_value = cond_timeout = 0;
+
+ gl_thread_create (thread, timedcond_routine, NULL);
+
+ remain = 2;
+ do
+ {
+ yield ();
+ remain = sleep (remain);
+ }
+ while (remain);
+
+ /* signal condition */
+ gl_lock_lock (lockcond);
+ cond_value = 1;
+ gl_cond_signal (condtest);
+ gl_lock_unlock (lockcond);
+
+ gl_thread_join (thread, NULL);
+
+ if (!cond_timeout)
+ abort ();
+}
+
+int
+main ()
+{
+#if TEST_PTH_THREADS
+ if (!pth_init ())
+ abort ();
+#endif
+
+#if DO_TEST_COND
+ printf ("Starting test_cond ...");
+ fflush (stdout);
+ test_cond ();
+ printf (" OK\n");
+ fflush (stdout);
+#endif
+#if DO_TEST_TIMEDCOND
+ printf ("Starting test_timedcond ...");
+ fflush (stdout);
+ test_timedcond ();
+ printf (" OK\n");
+ fflush (stdout);
+#endif
+
+ return 0;
+}
+
+#else
+
+/* No multithreading available. */
+
+int
+main ()
+{
+ return 77;
+}
+
+#endif
diff --git a/tests/test-lock.c b/tests/test-lock.c
index 2d10833..a620418 100644
--- a/tests/test-lock.c
+++ b/tests/test-lock.c
@@ -45,6 +45,9 @@
#define DO_TEST_RWLOCK 1
#define DO_TEST_RECURSIVE_LOCK 1
#define DO_TEST_ONCE 1
+#define DO_TEST_COND 1
+#define DO_TEST_TIMEDCOND 1
+
/* Whether to help the scheduler through explicit yield().
Uncomment this to see if the operating system has a fair scheduler. */
@@ -71,6 +74,9 @@
# undef USE_PTH_THREADS
# undef USE_WIN32_THREADS
#endif
+
+#include "glthread.h"
+#include "glcond.h"
#include "lock.h"
#if ENABLE_DEBUGGING
@@ -80,80 +86,29 @@
#endif
#if TEST_POSIX_THREADS
-# include
# include
-typedef pthread_t gl_thread_t;
-static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
-{
- pthread_t thread;
- if (pthread_create (&thread, NULL, func, arg) != 0)
- abort ();
- return thread;
-}
-static inline void gl_thread_join (gl_thread_t thread)
-{
- void *retval;
- if (pthread_join (thread, &retval) != 0)
- abort ();
-}
static inline void gl_thread_yield (void)
{
sched_yield ();
}
-static inline void * gl_thread_self (void)
-{
- return (void *) pthread_self ();
-}
#endif
+
#if TEST_PTH_THREADS
# include
-typedef pth_t gl_thread_t;
-static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
-{
- pth_t thread = pth_spawn (NULL, func, arg);
- if (thread == NULL)
- abort ();
- return thread;
-}
-static inline void gl_thread_join (gl_thread_t thread)
-{
- if (!pth_join (thread, NULL))
- abort ();
-}
static inline void gl_thread_yield (void)
{
pth_yield (NULL);
}
-static inline void * gl_thread_self (void)
-{
- return pth_self ();
-}
#endif
+
#if TEST_SOLARIS_THREADS
# include
-typedef thread_t gl_thread_t;
-static inline gl_thread_t gl_thread_create (void * (*func) (void *), void *arg)
-{
- thread_t thread;
- if (thr_create (NULL, 0, func, arg, 0, &thread) != 0)
- abort ();
- return thread;
-}
-static inline void gl_thread_join (gl_thread_t thread)
-{
- void *retval;
- if (thr_join (thread, NULL, &retval) != 0)
- abort ();
-}
static inline void gl_thread_yield (void)
{
thr_yield ();
}
-static inline void * gl_thread_self (void)
-{
- return (void *) thr_self ();
-}
#endif
+
#if TEST_WIN32_THREADS
# include
typedef HANDLE gl_thread_t;
@@ -244,9 +199,9 @@ lock_mutator_thread (void *arg)
{
int i1, i2, value;
- dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before lock\n", glthread_self ());
gl_lock_lock (my_lock);
- dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after lock\n", glthread_self ());
i1 = random_account ();
i2 = random_account ();
@@ -254,20 +209,20 @@ lock_mutator_thread (void *arg)
account[i1] += value;
account[i2] -= value;
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", glthread_self ());
gl_lock_unlock (my_lock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", glthread_self ());
- dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before check lock\n", glthread_self ());
gl_lock_lock (my_lock);
check_accounts ();
gl_lock_unlock (my_lock);
- dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after check unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", glthread_self ());
return NULL;
}
@@ -278,16 +233,16 @@ lock_checker_thread (void *arg)
{
while (!lock_checker_done)
{
- dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check lock\n", glthread_self ());
gl_lock_lock (my_lock);
check_accounts ();
gl_lock_unlock (my_lock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", glthread_self ());
return NULL;
}
@@ -304,15 +259,15 @@ test_lock (void)
lock_checker_done = 0;
/* Spawn the threads. */
- checkerthread = gl_thread_create (lock_checker_thread, NULL);
+ gl_thread_create (checkerthread, lock_checker_thread, NULL);
for (i = 0; i < THREAD_COUNT; i++)
- threads[i] = gl_thread_create (lock_mutator_thread, NULL);
+ gl_thread_create (threads[i], lock_mutator_thread, NULL);
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
lock_checker_done = 1;
- gl_thread_join (checkerthread);
+ gl_thread_join (checkerthread, NULL);
check_accounts ();
}
@@ -331,9 +286,9 @@ rwlock_mutator_thread (void *arg)
{
int i1, i2, value;
- dbgprintf ("Mutator %p before wrlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before wrlock\n", glthread_self ());
gl_rwlock_wrlock (my_rwlock);
- dbgprintf ("Mutator %p after wrlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after wrlock\n", glthread_self ());
i1 = random_account ();
i2 = random_account ();
@@ -341,14 +296,14 @@ rwlock_mutator_thread (void *arg)
account[i1] += value;
account[i2] -= value;
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", glthread_self ());
gl_rwlock_unlock (my_rwlock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", glthread_self ());
return NULL;
}
@@ -359,16 +314,16 @@ rwlock_checker_thread (void *arg)
{
while (!rwlock_checker_done)
{
- dbgprintf ("Checker %p before check rdlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check rdlock\n", glthread_self ());
gl_rwlock_rdlock (my_rwlock);
check_accounts ();
gl_rwlock_unlock (my_rwlock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", glthread_self ());
return NULL;
}
@@ -386,16 +341,16 @@ test_rwlock (void)
/* Spawn the threads. */
for (i = 0; i < THREAD_COUNT; i++)
- checkerthreads[i] = gl_thread_create (rwlock_checker_thread, NULL);
+ gl_thread_create (checkerthreads[i], rwlock_checker_thread, NULL);
for (i = 0; i < THREAD_COUNT; i++)
- threads[i] = gl_thread_create (rwlock_mutator_thread, NULL);
+ gl_thread_create (threads[i], rwlock_mutator_thread, NULL);
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
rwlock_checker_done = 1;
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (checkerthreads[i]);
+ gl_thread_join (checkerthreads[i], NULL);
check_accounts ();
}
@@ -410,9 +365,9 @@ recshuffle (void)
{
int i1, i2, value;
- dbgprintf ("Mutator %p before lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before lock\n", glthread_self ());
gl_recursive_lock_lock (my_reclock);
- dbgprintf ("Mutator %p after lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after lock\n", glthread_self ());
i1 = random_account ();
i2 = random_account ();
@@ -424,9 +379,9 @@ recshuffle (void)
if (((unsigned int) rand() >> 3) % 2)
recshuffle ();
- dbgprintf ("Mutator %p before unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before unlock\n", glthread_self ());
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Mutator %p after unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after unlock\n", glthread_self ());
}
static void *
@@ -438,16 +393,16 @@ reclock_mutator_thread (void *arg)
{
recshuffle ();
- dbgprintf ("Mutator %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p before check lock\n", glthread_self ());
gl_recursive_lock_lock (my_reclock);
check_accounts ();
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Mutator %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Mutator %p after check unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Mutator %p dying.\n", gl_thread_self ());
+ dbgprintf ("Mutator %p dying.\n", glthread_self ());
return NULL;
}
@@ -458,16 +413,16 @@ reclock_checker_thread (void *arg)
{
while (!reclock_checker_done)
{
- dbgprintf ("Checker %p before check lock\n", gl_thread_self ());
+ dbgprintf ("Checker %p before check lock\n", glthread_self ());
gl_recursive_lock_lock (my_reclock);
check_accounts ();
gl_recursive_lock_unlock (my_reclock);
- dbgprintf ("Checker %p after check unlock\n", gl_thread_self ());
+ dbgprintf ("Checker %p after check unlock\n", glthread_self ());
yield ();
}
- dbgprintf ("Checker %p dying.\n", gl_thread_self ());
+ dbgprintf ("Checker %p dying.\n", glthread_self ());
return NULL;
}
@@ -484,15 +439,15 @@ test_recursive_lock (void)
reclock_checker_done = 0;
/* Spawn the threads. */
- checkerthread = gl_thread_create (reclock_checker_thread, NULL);
+ gl_thread_create (checkerthread, reclock_checker_thread, NULL);
for (i = 0; i < THREAD_COUNT; i++)
- threads[i] = gl_thread_create (reclock_mutator_thread, NULL);
+ gl_thread_create (threads[i], reclock_mutator_thread, NULL);
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
reclock_checker_done = 1;
- gl_thread_join (checkerthread);
+ gl_thread_join (checkerthread, NULL);
check_accounts ();
}
@@ -533,10 +488,10 @@ once_contender_thread (void *arg)
gl_lock_unlock (ready_lock[id]);
if (repeat == REPEAT_COUNT)
- break;
+ break;
dbgprintf ("Contender %p waiting for signal for round %d\n",
- gl_thread_self (), repeat);
+ glthread_self (), repeat);
#if ENABLE_LOCKING
/* Wait for the signal to go. */
gl_rwlock_rdlock (fire_signal[repeat]);
@@ -545,10 +500,10 @@ once_contender_thread (void *arg)
#else
/* Wait for the signal to go. */
while (fire_signal_state <= repeat)
- yield ();
+ yield ();
#endif
dbgprintf ("Contender %p got the signal for round %d\n",
- gl_thread_self (), repeat);
+ glthread_self (), repeat);
/* Contend for execution. */
gl_once (once_control, once_execute);
@@ -582,37 +537,37 @@ test_once (void)
/* Spawn the threads. */
for (i = 0; i < THREAD_COUNT; i++)
- threads[i] = gl_thread_create (once_contender_thread, (void *) (long) i);
+ gl_thread_create (threads[i], once_contender_thread, (void *) (long) i);
for (repeat = 0; repeat <= REPEAT_COUNT; repeat++)
{
/* Wait until every thread is ready. */
dbgprintf ("Main thread before synchonizing for round %d\n", repeat);
for (;;)
- {
- int ready_count = 0;
- for (i = 0; i < THREAD_COUNT; i++)
- {
- gl_lock_lock (ready_lock[i]);
- ready_count += ready[i];
- gl_lock_unlock (ready_lock[i]);
- }
- if (ready_count == THREAD_COUNT)
- break;
- yield ();
- }
+ {
+ int ready_count = 0;
+ for (i = 0; i < THREAD_COUNT; i++)
+ {
+ gl_lock_lock (ready_lock[i]);
+ ready_count += ready[i];
+ gl_lock_unlock (ready_lock[i]);
+ }
+ if (ready_count == THREAD_COUNT)
+ break;
+ yield ();
+ }
dbgprintf ("Main thread after synchonizing for round %d\n", repeat);
if (repeat > 0)
- {
- /* Check that exactly one thread executed the once_execute()
- function. */
- if (performed != 1)
- abort ();
- }
+ {
+ /* Check that exactly one thread executed the once_execute()
+ function. */
+ if (performed != 1)
+ abort ();
+ }
if (repeat == REPEAT_COUNT)
- break;
+ break;
/* Preparation for the next round: Initialize once_control. */
memcpy (&once_control, &fresh_once, sizeof (gl_once_t));
@@ -622,11 +577,11 @@ test_once (void)
/* Preparation for the next round: Reset the ready flags. */
for (i = 0; i < THREAD_COUNT; i++)
- {
- gl_lock_lock (ready_lock[i]);
- ready[i] = 0;
- gl_lock_unlock (ready_lock[i]);
- }
+ {
+ gl_lock_lock (ready_lock[i]);
+ ready[i] = 0;
+ gl_lock_unlock (ready_lock[i]);
+ }
/* Signal all threads simultaneously. */
dbgprintf ("Main thread giving signal for round %d\n", repeat);
@@ -639,7 +594,7 @@ test_once (void)
/* Wait for the threads to terminate. */
for (i = 0; i < THREAD_COUNT; i++)
- gl_thread_join (threads[i]);
+ gl_thread_join (threads[i], NULL);
}
int