From 833244ddbb8c8150519915d5f67e789dcb588400 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Sun, 2 Jul 2006 02:55:41 +0000 Subject: [PATCH] Unix thread support --- acx_pthread.m4 | 473 +++++++++++++++++---------------- configure.ac | 1 + xmltooling/Makefile.am | 2 +- xmltooling/util/PThreads.cpp | 604 +++++++++++++++++++++--------------------- xmltooling/util/Threads.h | 618 +++++++++++++++++++++---------------------- 5 files changed, 855 insertions(+), 843 deletions(-) diff --git a/acx_pthread.m4 b/acx_pthread.m4 index ba6c09c..1f2a56e 100644 --- a/acx_pthread.m4 +++ b/acx_pthread.m4 @@ -1,232 +1,241 @@ -dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl This macro figures out how to build C programs using POSIX -dnl threads. It sets the PTHREAD_LIBS output variable to the threads -dnl library and linker flags, and the PTHREAD_CFLAGS output variable -dnl to any special C compiler flags that are needed. (The user can also -dnl force certain compiler flags/libs to be tested by setting these -dnl environment variables.) -dnl -dnl Also sets PTHREAD_CC to any special C compiler that is needed for -dnl multi-threaded programs (defaults to the value of CC otherwise). -dnl (This is necessary on AIX to use the special cc_r compiler alias.) -dnl -dnl If you are only building threads programs, you may wish to -dnl use these variables in your default LIBS, CFLAGS, and CC: -dnl -dnl LIBS="$PTHREAD_LIBS $LIBS" -dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -dnl CC="$PTHREAD_CC" -dnl -dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute -dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE -dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -dnl -dnl ACTION-IF-FOUND is a list of shell commands to run if a threads -dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands -dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, -dnl the default action will define HAVE_PTHREAD. -dnl -dnl Please let the authors know if this macro fails on any platform, -dnl or if you have any other suggestions or comments. This macro was -dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) -dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread -dnl macros posted by AFC to the autoconf macro repository. We are also -dnl grateful for the helpful feedback of numerous users. -dnl -dnl @author Steven G. Johnson and Alejandro Forero Cuervo - -AC_DEFUN([ACX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_SAVE -AC_LANG_C -acx_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) - AC_MSG_RESULT($acx_pthread_ok) - if test x"$acx_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all. - -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# pthread: Linux, etcetera -# --thread-safe: KAI C++ - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthread or - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" - ;; -esac - -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_TRY_LINK([#include ], - [pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], - [acx_pthread_ok=yes]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT($acx_pthread_ok) - if test "x$acx_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: threads are created detached by default - # and the JOINABLE attribute has a nonstandard name (UNDETACHED). - AC_MSG_CHECKING([for joinable pthread attribute]) - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_JOINABLE;], - ok=PTHREAD_CREATE_JOINABLE, ok=unknown) - if test x"$ok" = xunknown; then - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_UNDETACHED;], - ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) - fi - if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then - AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, - [Define to the necessary symbol if this constant - uses a non-standard name on your system.]) - fi - AC_MSG_RESULT(${ok}) - if test x"$ok" = xunknown; then - AC_MSG_WARN([we do not know how to create joinable pthreads]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; - *-osf* | *-hpux*) flag="-D_REENTRANT";; - *solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: must compile with cc_r - AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) -else - PTHREAD_CC="$CC" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - acx_pthread_ok=no - $2 -fi -AC_LANG_RESTORE -])dnl ACX_PTHREAD +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl This macro figures out how to build C programs using POSIX +dnl threads. It sets the PTHREAD_LIBS output variable to the threads +dnl library and linker flags, and the PTHREAD_CFLAGS output variable +dnl to any special C compiler flags that are needed. (The user can also +dnl force certain compiler flags/libs to be tested by setting these +dnl environment variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl If you are only building threads programs, you may wish to +dnl use these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE +dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands +dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, +dnl the default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, +dnl or if you have any other suggestions or comments. This macro was +dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) +dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread +dnl macros posted by AFC to the autoconf macro repository. We are also +dnl grateful for the helpful feedback of numerous users. +dnl +dnl @author Steven G. Johnson and Alejandro Forero Cuervo + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; + *-osf* | *-hpux*) flag="-D_REENTRANT";; + *solaris*) + if test "$GCC" = "yes"; then + flag="-D_REENTRANT" + else + flag="-mt -D_REENTRANT" + fi + ;; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi + +saveCFLAGS="$CFLAGS" +saveLIBS="$LIBS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +LIBS="$LIBS $PTHREAD_LIBS" +AC_CHECK_FUNCS([pthread_rwlock_init]) +LIBS="$saveLIBS" +CFLAGS="$saveCFLAGS" + +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/configure.ac b/configure.ac index cf3b09c..1f269d9 100644 --- a/configure.ac +++ b/configure.ac @@ -5,6 +5,7 @@ AM_CONFIG_HEADER(xmltooling/config_pub.h) AM_INIT_AUTOMAKE([xmltooling], [1.0]) sinclude(doxygen.m4) +sinclude(acx_pthread.m4) # Docygen features DX_HTML_FEATURE(ON) diff --git a/xmltooling/Makefile.am b/xmltooling/Makefile.am index 9681b81..a907fb2 100644 --- a/xmltooling/Makefile.am +++ b/xmltooling/Makefile.am @@ -89,7 +89,7 @@ xmlsec_sources = endif if BUILD_PTHREAD -thread_sources = PThread.cpp +thread_sources = util/PThreads.cpp else thread_sources = endif diff --git a/xmltooling/util/PThreads.cpp b/xmltooling/util/PThreads.cpp index 0678e2e..2f9a1d0 100644 --- a/xmltooling/util/PThreads.cpp +++ b/xmltooling/util/PThreads.cpp @@ -1,301 +1,303 @@ -/* - * Copyright 2001-2005 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * PThreads.cpp - * - * Thread and locking wrappers for POSIX platforms - */ - -#include "internal.h" -#include "util/Threads.h" - -#include -#include - -#ifdef HAVE_PTHREAD -# include -# ifndef HAVE_PTHREAD_RWLOCK_INIT -# include -# endif -#else -# error "This implementation is for POSIX platforms." -#endif - -using namespace xmltooling; -using namespace log4cpp; -using namespace std; - -namespace xmltooling { - - class XMLTOOL_DLLLOCAL ThreadImpl : public Thread { - pthread_t thread_id; - public: - ThreadImpl(void* (*start_routine)(void*), void* arg); - virtual ~ThreadImpl() {} - - int detach() { - return pthread_detach(thread_id); - } - - int join(void** thread_return) { - return pthread_join(thread_id, thread_return); - } - - int kill(int signo) { - return pthread_kill(thread_id, signo); - } - }; - - class XMLTOOL_DLLLOCAL MutexImpl : public Mutex { - pthread_mutex_t mutex; - public: - MutexImpl(); - virtual ~MutexImpl() { - pthread_mutex_destroy(&mutex); - } - - int lock() { - return pthread_mutex_lock(&mutex); - } - - int unlock() { - return pthread_mutex_unlock(&mutex); - } - }; - - class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait { - pthread_cond_t cond; - public: - CondWaitImpl(); - virtual ~CondWaitImpl() { - pthread_cond_destroy(&cond); - } - - int wait(Mutex* mutex) { - return wait(static_cast(mutex)); - } - - int wait(MutexImpl* mutex) { - return pthread_cond_wait(&cond, &(mutex->mutex)); - } - - int timedwait(Mutex* mutex, int delay_seconds) { - return timedwait(static_cast(mutex), delay_seconds); - } - - int timedwait(MutexImpl* mutex, int delay_seconds) { - struct timespec ts; - memset(&ts, 0, sizeof(ts)); - ts.tv_sec = time(NULL) + delay_seconds; - return pthread_cond_timedwait(&cond, &(mutex->mutex), &ts); - } - - int signal() { - return pthread_cond_signal(&cond); - } - - int broadcast() { - return pthread_cond_broadcast(&cond); - } - }; - - class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock { -#ifdef HAVE_PTHREAD_RWLOCK_INIT - pthread_rwlock_t lock; - public: - RWLockImpl(); - virtual ~RWLockImpl() { - pthread_rwlock_destroy(&lock); - } - - int rdlock() { - return pthread_rwlock_rdlock(&lock); - } - - int wrlock() { - return pthread_rwlock_wrlock(&lock); - } - - int unlock() { - return pthread_rwlock_unlock(&lock); - } -#else - rwlock_t lock; - public: - RWLockImpl(); - virtual ~RWLockImpl() { - rwlock_destroy (&lock); - } - - int rdlock() { - return rw_rdlock(&lock); - } - - int wrlock() { - return rw_wrlock(&lock); - } - - int unlock() { - return rw_unlock(&lock); - } -#endif - }; - - class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey { - pthread_key_t key; - public: - ThreadKeyImpl(void (*destroy_fcn)(void*)); - virtual ~ThreadKeyImpl() { - pthread_key_delete(key); - } - - int setData(void* data) { - return pthread_setspecific(key,data); - } - - void* getData() const { - return pthread_getspecific(key); - } - }; - -}; - -ThreadImpl::ThreadImpl(void* (*start_routine)(void*), void* arg) -{ - int rc=pthread_create(&thread_id, NULL, start_routine, arg); - if (rc) { -#ifdef HAVE_STRERROR_R - char buf[256]; - strerror_r(rc,buf,sizeof(buf)); - buf[255]=0; - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,buf); -#else - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,strerror(rc)); -#endif - throw ThreadingException("Thread creation failed."); - } -} - -MutexImpl::MutexImpl() -{ - int rc=pthread_mutex_init(&mutex, NULL); - if (rc) { -#ifdef HAVE_STRERROR_R - char buf[256]; - strerror_r(rc,buf,sizeof(buf)); - buf[255]=0; - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,buf); -#else - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc)); -#endif - throw ThreadingException("Mutex creation failed."); - } -} - -CondWaitImpl::CondWaitImpl() -{ - int rc=pthread_cond_init(&cond, NULL); - if (rc) { -#ifdef HAVE_STRERROR_R - char buf[256]; - strerror_r(rc,buf,sizeof(buf)); - buf[255]=0; - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,buf); -#else - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc)); -#endif - throw ThreadingException("Condition variable creation failed."); - } -} - -RWLockImpl::RWLockImpl() -{ -#ifdef HAVE_PTHREAD_RWLOCK_INIT - int rc=pthread_rwlock_init(&lock, NULL); -#else - int rc=rwlock_init(&lock, USYNC_THREAD, NULL); -#endif - if (rc) { -#ifdef HAVE_STRERROR_R - char buf[256]; - strerror_r(rc,buf,sizeof(buf)); - buf[255]=0; - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,buf); -#else - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc)); -#endif - throw ThreadingException("Shared lock creation failed."); - } -} - -ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*)) -{ - int rc=pthread_key_create(&key, destroy_fcn); - if (rc) { -#ifdef HAVE_STRERROR_R - char buf[256]; - strerror_r(rc,buf,sizeof(buf)); - buf[255]=0; - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,buf); -#else - Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,strerror(rc)); -#endif - throw ThreadingException("Thread key creation failed."); - } -} - -Thread* Thread::create(void* (*start_routine)(void*), void* arg) -{ - return new ThreadImpl(start_routine, arg); -} - -void Thread::exit(void* return_val) -{ - pthread_exit(return_val); -} - -void Thread::mask_all_signals(void) -{ - sigset_t sigmask; - sigfillset(&sigmask); - Thread::mask_signals(SIG_BLOCK, &sigmask, NULL); -} - -int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask) -{ - return pthread_sigmask(how,newmask,oldmask); -} - -Mutex * Mutex::create() -{ - return new MutexImpl(); -} - -CondWait * CondWait::create() -{ - return new CondWaitImpl(); -} - -RWLock * RWLock::create() -{ - return new RWLockImpl(); -} - -ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*)) -{ - return new ThreadKeyImpl(destroy_fcn); -} +/* + * Copyright 2001-2005 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * PThreads.cpp + * + * Thread and locking wrappers for POSIX platforms + */ + +#include "internal.h" +#include "util/Threads.h" + +#include +#include +#include + +#ifdef HAVE_PTHREAD +# include +# ifndef HAVE_PTHREAD_RWLOCK_INIT +# include +# endif +#else +# error "This implementation is for POSIX platforms." +#endif + +using namespace xmltooling; +using namespace log4cpp; +using namespace std; + +namespace xmltooling { + + class XMLTOOL_DLLLOCAL ThreadImpl : public Thread { + pthread_t thread_id; + public: + ThreadImpl(void* (*start_routine)(void*), void* arg); + virtual ~ThreadImpl() {} + + int detach() { + return pthread_detach(thread_id); + } + + int join(void** thread_return) { + return pthread_join(thread_id, thread_return); + } + + int kill(int signo) { + return pthread_kill(thread_id, signo); + } + }; + + class XMLTOOL_DLLLOCAL MutexImpl : public Mutex { + pthread_mutex_t mutex; + friend class XMLTOOL_DLLLOCAL CondWaitImpl; + public: + MutexImpl(); + virtual ~MutexImpl() { + pthread_mutex_destroy(&mutex); + } + + int lock() { + return pthread_mutex_lock(&mutex); + } + + int unlock() { + return pthread_mutex_unlock(&mutex); + } + }; + + class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait { + pthread_cond_t cond; + public: + CondWaitImpl(); + virtual ~CondWaitImpl() { + pthread_cond_destroy(&cond); + } + + int wait(Mutex* mutex) { + return wait(static_cast(mutex)); + } + + int wait(MutexImpl* mutex) { + return pthread_cond_wait(&cond, &(mutex->mutex)); + } + + int timedwait(Mutex* mutex, int delay_seconds) { + return timedwait(static_cast(mutex), delay_seconds); + } + + int timedwait(MutexImpl* mutex, int delay_seconds) { + struct timespec ts; + memset(&ts, 0, sizeof(ts)); + ts.tv_sec = time(NULL) + delay_seconds; + return pthread_cond_timedwait(&cond, &(mutex->mutex), &ts); + } + + int signal() { + return pthread_cond_signal(&cond); + } + + int broadcast() { + return pthread_cond_broadcast(&cond); + } + }; + + class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock { +#ifdef HAVE_PTHREAD_RWLOCK_INIT + pthread_rwlock_t lock; + public: + RWLockImpl(); + virtual ~RWLockImpl() { + pthread_rwlock_destroy(&lock); + } + + int rdlock() { + return pthread_rwlock_rdlock(&lock); + } + + int wrlock() { + return pthread_rwlock_wrlock(&lock); + } + + int unlock() { + return pthread_rwlock_unlock(&lock); + } +#else + rwlock_t lock; + public: + RWLockImpl(); + virtual ~RWLockImpl() { + rwlock_destroy (&lock); + } + + int rdlock() { + return rw_rdlock(&lock); + } + + int wrlock() { + return rw_wrlock(&lock); + } + + int unlock() { + return rw_unlock(&lock); + } +#endif + }; + + class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey { + pthread_key_t key; + public: + ThreadKeyImpl(void (*destroy_fcn)(void*)); + virtual ~ThreadKeyImpl() { + pthread_key_delete(key); + } + + int setData(void* data) { + return pthread_setspecific(key,data); + } + + void* getData() const { + return pthread_getspecific(key); + } + }; + +}; + +ThreadImpl::ThreadImpl(void* (*start_routine)(void*), void* arg) +{ + int rc=pthread_create(&thread_id, NULL, start_routine, arg); + if (rc) { +#ifdef HAVE_STRERROR_R + char buf[256]; + strerror_r(rc,buf,sizeof(buf)); + buf[255]=0; + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,buf); +#else + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,strerror(rc)); +#endif + throw ThreadingException("Thread creation failed."); + } +} + +MutexImpl::MutexImpl() +{ + int rc=pthread_mutex_init(&mutex, NULL); + if (rc) { +#ifdef HAVE_STRERROR_R + char buf[256]; + strerror_r(rc,buf,sizeof(buf)); + buf[255]=0; + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,buf); +#else + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc)); +#endif + throw ThreadingException("Mutex creation failed."); + } +} + +CondWaitImpl::CondWaitImpl() +{ + int rc=pthread_cond_init(&cond, NULL); + if (rc) { +#ifdef HAVE_STRERROR_R + char buf[256]; + strerror_r(rc,buf,sizeof(buf)); + buf[255]=0; + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,buf); +#else + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc)); +#endif + throw ThreadingException("Condition variable creation failed."); + } +} + +RWLockImpl::RWLockImpl() +{ +#ifdef HAVE_PTHREAD_RWLOCK_INIT + int rc=pthread_rwlock_init(&lock, NULL); +#else + int rc=rwlock_init(&lock, USYNC_THREAD, NULL); +#endif + if (rc) { +#ifdef HAVE_STRERROR_R + char buf[256]; + strerror_r(rc,buf,sizeof(buf)); + buf[255]=0; + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,buf); +#else + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc)); +#endif + throw ThreadingException("Shared lock creation failed."); + } +} + +ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*)) +{ + int rc=pthread_key_create(&key, destroy_fcn); + if (rc) { +#ifdef HAVE_STRERROR_R + char buf[256]; + strerror_r(rc,buf,sizeof(buf)); + buf[255]=0; + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,buf); +#else + Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,strerror(rc)); +#endif + throw ThreadingException("Thread key creation failed."); + } +} + +Thread* Thread::create(void* (*start_routine)(void*), void* arg) +{ + return new ThreadImpl(start_routine, arg); +} + +void Thread::exit(void* return_val) +{ + pthread_exit(return_val); +} + +void Thread::mask_all_signals(void) +{ + sigset_t sigmask; + sigfillset(&sigmask); + Thread::mask_signals(SIG_BLOCK, &sigmask, NULL); +} + +int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask) +{ + return pthread_sigmask(how,newmask,oldmask); +} + +Mutex * Mutex::create() +{ + return new MutexImpl(); +} + +CondWait * CondWait::create() +{ + return new CondWaitImpl(); +} + +RWLock * RWLock::create() +{ + return new RWLockImpl(); +} + +ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*)) +{ + return new ThreadKeyImpl(destroy_fcn); +} diff --git a/xmltooling/util/Threads.h b/xmltooling/util/Threads.h index ef9231b..2d6c5c3 100644 --- a/xmltooling/util/Threads.h +++ b/xmltooling/util/Threads.h @@ -1,309 +1,309 @@ -/* - * Copyright 2001-2006 Internet2 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file Threads.h - * - * Thread and locking wrappers - */ - -#ifndef _xmltooling_threads_h -#define _xmltooling_threads_h - -#include -#include - -namespace xmltooling -{ - DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations); - - /** - * A class for manual thread creation and synchronization. - */ - class XMLTOOL_API Thread - { - MAKE_NONCOPYABLE(Thread); - public: - Thread() {} - virtual ~Thread() {} - - /** - * Disassociate from the thread. - * - * @return 0 for success, non-zero for failure - */ - virtual int detach()=0; - - /** - * Join with the thread and wait for its completion. - * - * @param thread_return holds the return value of the thread routine - * @return 0 for success, non-zero for failure - */ - virtual int join(void** thread_return)=0; - - /** - * Kill the thread. - * - * @param signo the signal to send to the thread - * @return 0 for success, non-zero for failure - */ - virtual int kill(int signo)=0; - - /** - * Creates a new thread object to run the supplied start routine. - * - * @param start_routine the function to execute on the thread - * @param arg a parameter for the start routine - * @return the created and running thread object - */ - static Thread* create(void* (*start_routine)(void*), void* arg); - - /** - * Exits a thread gracefully. - * - * @param return_val the return value for the thread - */ - static void exit(void* return_val); - -#ifndef WIN32 - /** - * Masks all signals from a thread. - */ - static void mask_all_signals(void); - - /** - * Masks specific signals from a thread. - * - * @param how - * @param newmask the new signal mask - * @param oldmask the old signal mask - * @return 0 for success, non-zero for failure - */ - static int mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask); -#endif - }; - - /** - * A class for managing Thread Local Storage values. - */ - class XMLTOOL_API ThreadKey - { - MAKE_NONCOPYABLE(ThreadKey); - public: - ThreadKey() {} - virtual ~ThreadKey() {} - - /** - * Sets the value for a TLS key. - * - * @param data the value to set - * @return 0 for success, non-zero for failure - */ - virtual int setData(void* data)=0; - - /** - * Returns the value for a TLS key. - * - * @return the value or NULL - */ - virtual void* getData() const=0; - - /** - * Creates a new TLS key. - * - * @param destroy_fn a functon to cleanup key values - * @return the new key - */ - static ThreadKey* create(void (*destroy_fn)(void*)); - }; - - /** - * A class for managing exclusive access to resources. - */ - class XMLTOOL_API Mutex - { - MAKE_NONCOPYABLE(Mutex); - public: - Mutex() {} - virtual ~Mutex() {} - - /** - * Locks the mutex for exclusive access. - * - * @return 0 for success, non-zero for failure - */ - virtual int lock()=0; - - /** - * Unlocks the mutex for exclusive access. - * - * @return 0 for success, non-zero for failure - */ - virtual int unlock()=0; - - /** - * Creates a new mutex object. - * - * @return the new mutex - */ - static Mutex* create(); - }; - - /** - * A class for managing shared and exclusive access to resources. - */ - class XMLTOOL_API RWLock - { - MAKE_NONCOPYABLE(RWLock); - public: - RWLock() {} - virtual ~RWLock() {} - - /** - * Obtains a shared lock. - * - * @return 0 for success, non-zero for failure - */ - virtual int rdlock()=0; - - /** - * Obtains an exclusive lock. - * - * @return 0 for success, non-zero for failure - */ - virtual int wrlock()=0; - - /** - * Unlocks the lock. - * - * @return 0 for success, non-zero for failure - */ - virtual int unlock()=0; - - /** - * Creates a new read/write lock. - * - * @return the new lock - */ - static RWLock* create(); - }; - - /** - * A class for establishing queues on a mutex based on a periodic condition. - */ - class XMLTOOL_API CondWait - { - MAKE_NONCOPYABLE(CondWait); - public: - CondWait() {} - virtual ~CondWait() {} - - /** - * Waits for a condition variable using the supplied mutex as a queue. - * - * @param lock mutex to queue on - * @return 0 for success, non-zero for failure - */ - virtual int wait(Mutex* lock)=0; - - /** - * Waits for a condition variable using the supplied mutex as a queue, - * but only for a certain time limit. - * - * @param lock mutex to queue on - * @param delay_seconds maximum time to wait before waking up - * @return 0 for success, non-zero for failure - */ - virtual int timedwait(Mutex* lock, int delay_seconds)=0; - - /** - * Signal a single thread to wake up if a condition changes. - * - * @return 0 for success, non-zero for failure - */ - virtual int signal()=0; - - /** - * Signal all threads to wake up if a condition changes. - * - * @return 0 for success, non-zero for failure - */ - virtual int broadcast()=0; - - /** - * Creates a new condition variable. - * - * @return the new condition variable - */ - static CondWait* create(); - }; - - /** - * RAII wrapper for a mutex lock. - */ - class XMLTOOL_API Lock { - MAKE_NONCOPYABLE(Lock); - public: - /** - * Locks and wraps the designated mutex. - * - * @param mtx mutex to lock - */ - Lock(Mutex* mtx) : mutex(mtx) { - mutex->lock(); - } - - /** - * Unlocks the wrapped mutex. - */ - ~Lock() { - mutex->unlock(); - } - - private: - Mutex* mutex; - }; - - /** - * RAII wrapper for a shared lock. - */ - class XMLTOOL_API ReadLock { - MAKE_NONCOPYABLE(ReadLock); - public: - /** - * Locks and wraps the designated shared lock. - * - * @param lock lock to acquire - */ - ReadLock(RWLock* lock) : rwlock(lock) { - rwlock->rdlock(); - } - - /** - * Unlocks the wrapped shared lock. - */ - ~ReadLock() { - rwlock->unlock(); - } - - private: - RWLock* rwlock; - }; - -} - -#endif /* _xmltooling_threads_h */ +/* + * Copyright 2001-2006 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Threads.h + * + * Thread and locking wrappers + */ + +#ifndef _xmltooling_threads_h +#define _xmltooling_threads_h + +#include +#include + +namespace xmltooling +{ + DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations); + + /** + * A class for manual thread creation and synchronization. + */ + class XMLTOOL_API Thread + { + MAKE_NONCOPYABLE(Thread); + public: + Thread() {} + virtual ~Thread() {} + + /** + * Disassociate from the thread. + * + * @return 0 for success, non-zero for failure + */ + virtual int detach()=0; + + /** + * Join with the thread and wait for its completion. + * + * @param thread_return holds the return value of the thread routine + * @return 0 for success, non-zero for failure + */ + virtual int join(void** thread_return)=0; + + /** + * Kill the thread. + * + * @param signo the signal to send to the thread + * @return 0 for success, non-zero for failure + */ + virtual int kill(int signo)=0; + + /** + * Creates a new thread object to run the supplied start routine. + * + * @param start_routine the function to execute on the thread + * @param arg a parameter for the start routine + * @return the created and running thread object + */ + static Thread* create(void* (*start_routine)(void*), void* arg); + + /** + * Exits a thread gracefully. + * + * @param return_val the return value for the thread + */ + static void exit(void* return_val); + +#ifndef WIN32 + /** + * Masks all signals from a thread. + */ + static void mask_all_signals(void); + + /** + * Masks specific signals from a thread. + * + * @param how + * @param newmask the new signal mask + * @param oldmask the old signal mask + * @return 0 for success, non-zero for failure + */ + static int mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask); +#endif + }; + + /** + * A class for managing Thread Local Storage values. + */ + class XMLTOOL_API ThreadKey + { + MAKE_NONCOPYABLE(ThreadKey); + public: + ThreadKey() {} + virtual ~ThreadKey() {} + + /** + * Sets the value for a TLS key. + * + * @param data the value to set + * @return 0 for success, non-zero for failure + */ + virtual int setData(void* data)=0; + + /** + * Returns the value for a TLS key. + * + * @return the value or NULL + */ + virtual void* getData() const=0; + + /** + * Creates a new TLS key. + * + * @param destroy_fn a functon to cleanup key values + * @return the new key + */ + static ThreadKey* create(void (*destroy_fn)(void*)); + }; + + /** + * A class for managing exclusive access to resources. + */ + class XMLTOOL_API Mutex + { + MAKE_NONCOPYABLE(Mutex); + public: + Mutex() {} + virtual ~Mutex() {} + + /** + * Locks the mutex for exclusive access. + * + * @return 0 for success, non-zero for failure + */ + virtual int lock()=0; + + /** + * Unlocks the mutex for exclusive access. + * + * @return 0 for success, non-zero for failure + */ + virtual int unlock()=0; + + /** + * Creates a new mutex object. + * + * @return the new mutex + */ + static Mutex* create(); + }; + + /** + * A class for managing shared and exclusive access to resources. + */ + class XMLTOOL_API RWLock + { + MAKE_NONCOPYABLE(RWLock); + public: + RWLock() {} + virtual ~RWLock() {} + + /** + * Obtains a shared lock. + * + * @return 0 for success, non-zero for failure + */ + virtual int rdlock()=0; + + /** + * Obtains an exclusive lock. + * + * @return 0 for success, non-zero for failure + */ + virtual int wrlock()=0; + + /** + * Unlocks the lock. + * + * @return 0 for success, non-zero for failure + */ + virtual int unlock()=0; + + /** + * Creates a new read/write lock. + * + * @return the new lock + */ + static RWLock* create(); + }; + + /** + * A class for establishing queues on a mutex based on a periodic condition. + */ + class XMLTOOL_API CondWait + { + MAKE_NONCOPYABLE(CondWait); + public: + CondWait() {} + virtual ~CondWait() {} + + /** + * Waits for a condition variable using the supplied mutex as a queue. + * + * @param lock mutex to queue on + * @return 0 for success, non-zero for failure + */ + virtual int wait(Mutex* lock)=0; + + /** + * Waits for a condition variable using the supplied mutex as a queue, + * but only for a certain time limit. + * + * @param lock mutex to queue on + * @param delay_seconds maximum time to wait before waking up + * @return 0 for success, non-zero for failure + */ + virtual int timedwait(Mutex* lock, int delay_seconds)=0; + + /** + * Signal a single thread to wake up if a condition changes. + * + * @return 0 for success, non-zero for failure + */ + virtual int signal()=0; + + /** + * Signal all threads to wake up if a condition changes. + * + * @return 0 for success, non-zero for failure + */ + virtual int broadcast()=0; + + /** + * Creates a new condition variable. + * + * @return the new condition variable + */ + static CondWait* create(); + }; + + /** + * RAII wrapper for a mutex lock. + */ + class XMLTOOL_API Lock { + MAKE_NONCOPYABLE(Lock); + public: + /** + * Locks and wraps the designated mutex. + * + * @param mtx mutex to lock + */ + Lock(Mutex* mtx) : mutex(mtx) { + mutex->lock(); + } + + /** + * Unlocks the wrapped mutex. + */ + ~Lock() { + mutex->unlock(); + } + + private: + Mutex* mutex; + }; + + /** + * RAII wrapper for a shared lock. + */ + class XMLTOOL_API ReadLock { + MAKE_NONCOPYABLE(ReadLock); + public: + /** + * Locks and wraps the designated shared lock. + * + * @param lock lock to acquire + */ + ReadLock(RWLock* lock) : rwlock(lock) { + rwlock->rdlock(); + } + + /** + * Unlocks the wrapped shared lock. + */ + ~ReadLock() { + rwlock->unlock(); + } + + private: + RWLock* rwlock; + }; + +} + +#endif /* _xmltooling_threads_h */ -- 2.1.4