diff --git a/lib/glcond.h b/lib/glcond.h
new file mode 100644
index 0000000..181ec4a
--- /dev/null
+++ b/lib/glcond.h
@@ -0,0 +1,323 @@
+/* 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 glhread_cond_destroy(COND) \
+ (void)
+
+#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..f0e59f1
--- /dev/null
+++ b/lib/glthread.h
@@ -0,0 +1,274 @@
+/* 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(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(&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..b31d6ae
--- /dev/null
+++ b/m4/glcond.m4
@@ -0,0 +1,10 @@
+# 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_REQUIRE([gl_LOCK])
+])
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/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..68bc074 100644
--- a/modules/lock-tests
+++ b/modules/lock-tests
@@ -2,6 +2,8 @@ Files:
tests/test-lock.c
Depends-on:
+glthread
+glcond
configure.ac:
dnl Checks for special libraries for the tests/test-lock test.
diff --git a/tests/test-lock.c b/tests/test-lock.c
index 2d10833..04ebb1c 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,117 @@ 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);
+}
+
+/*
+ * 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;
+}
+
+void
+test_timedcond()
+{
+ 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
@@ -670,6 +735,16 @@ main ()
test_once ();
printf (" OK\n"); fflush (stdout);
#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;
}