doc \
schemas \
cpp-xmltooling.sln \
+ acx_pthread.m4 \
+ acinclude.m4 \
libtool.m4 \
doxygen.m4 \
depcomp \
--- /dev/null
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])\r
+dnl\r
+dnl This macro figures out how to build C programs using POSIX\r
+dnl threads. It sets the PTHREAD_LIBS output variable to the threads\r
+dnl library and linker flags, and the PTHREAD_CFLAGS output variable\r
+dnl to any special C compiler flags that are needed. (The user can also\r
+dnl force certain compiler flags/libs to be tested by setting these\r
+dnl environment variables.)\r
+dnl\r
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for\r
+dnl multi-threaded programs (defaults to the value of CC otherwise).\r
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)\r
+dnl\r
+dnl If you are only building threads programs, you may wish to\r
+dnl use these variables in your default LIBS, CFLAGS, and CC:\r
+dnl\r
+dnl LIBS="$PTHREAD_LIBS $LIBS"\r
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"\r
+dnl CC="$PTHREAD_CC"\r
+dnl\r
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute\r
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE\r
+dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).\r
+dnl\r
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads\r
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands\r
+dnl to run it if it is not found. If ACTION-IF-FOUND is not specified,\r
+dnl the default action will define HAVE_PTHREAD.\r
+dnl\r
+dnl Please let the authors know if this macro fails on any platform,\r
+dnl or if you have any other suggestions or comments. This macro was\r
+dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)\r
+dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread\r
+dnl macros posted by AFC to the autoconf macro repository. We are also\r
+dnl grateful for the helpful feedback of numerous users.\r
+dnl\r
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>\r
+\r
+AC_DEFUN([ACX_PTHREAD], [\r
+AC_REQUIRE([AC_CANONICAL_HOST])\r
+AC_LANG_SAVE\r
+AC_LANG_C\r
+acx_pthread_ok=no\r
+\r
+# We used to check for pthread.h first, but this fails if pthread.h\r
+# requires special compiler flags (e.g. on True64 or Sequent).\r
+# It gets checked for in the link test anyway.\r
+\r
+# First of all, check if the user has set any of the PTHREAD_LIBS,\r
+# etcetera environment variables, and if threads linking works using\r
+# them:\r
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then\r
+ save_CFLAGS="$CFLAGS"\r
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"\r
+ save_LIBS="$LIBS"\r
+ LIBS="$PTHREAD_LIBS $LIBS"\r
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])\r
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)\r
+ AC_MSG_RESULT($acx_pthread_ok)\r
+ if test x"$acx_pthread_ok" = xno; then\r
+ PTHREAD_LIBS=""\r
+ PTHREAD_CFLAGS=""\r
+ fi\r
+ LIBS="$save_LIBS"\r
+ CFLAGS="$save_CFLAGS"\r
+fi\r
+\r
+# We must check for the threads library under a number of different\r
+# names; the ordering is very important because some systems\r
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the\r
+# libraries is broken (non-POSIX).\r
+\r
+# Create a list of thread flags to try. Items starting with a "-" are\r
+# C compiler flags, and other items are library names, except for "none"\r
+# which indicates that we try without any flags at all.\r
+\r
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt"\r
+\r
+# The ordering *is* (sometimes) important. Some notes on the\r
+# individual items follow:\r
+\r
+# pthreads: AIX (must check this before -lpthread)\r
+# none: in case threads are in libc; should be tried before -Kthread and\r
+# other compiler flags to prevent continual compiler warnings\r
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)\r
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)\r
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)\r
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)\r
+# -pthreads: Solaris/gcc\r
+# -mthreads: Mingw32/gcc, Lynx/gcc\r
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it\r
+# doesn't hurt to check since this sometimes defines pthreads too;\r
+# also defines -D_REENTRANT)\r
+# pthread: Linux, etcetera\r
+# --thread-safe: KAI C++\r
+\r
+case "${host_cpu}-${host_os}" in\r
+ *solaris*)\r
+\r
+ # On Solaris (at least, for some versions), libc contains stubbed\r
+ # (non-functional) versions of the pthreads routines, so link-based\r
+ # tests will erroneously succeed. (We need to link with -pthread or\r
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather\r
+ # a function called by this macro, so we could check for that, but\r
+ # who knows whether they'll stub that too in a future libc.) So,\r
+ # we'll just look for -pthreads and -lpthread first:\r
+\r
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"\r
+ ;;\r
+esac\r
+\r
+if test x"$acx_pthread_ok" = xno; then\r
+for flag in $acx_pthread_flags; do\r
+\r
+ case $flag in\r
+ none)\r
+ AC_MSG_CHECKING([whether pthreads work without any flags])\r
+ ;;\r
+\r
+ -*)\r
+ AC_MSG_CHECKING([whether pthreads work with $flag])\r
+ PTHREAD_CFLAGS="$flag"\r
+ ;;\r
+\r
+ *)\r
+ AC_MSG_CHECKING([for the pthreads library -l$flag])\r
+ PTHREAD_LIBS="-l$flag"\r
+ ;;\r
+ esac\r
+\r
+ save_LIBS="$LIBS"\r
+ save_CFLAGS="$CFLAGS"\r
+ LIBS="$PTHREAD_LIBS $LIBS"\r
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"\r
+\r
+ # Check for various functions. We must include pthread.h,\r
+ # since some functions may be macros. (On the Sequent, we\r
+ # need a special flag -Kthread to make this header compile.)\r
+ # We check for pthread_join because it is in -lpthread on IRIX\r
+ # while pthread_create is in libc. We check for pthread_attr_init\r
+ # due to DEC craziness with -lpthreads. We check for\r
+ # pthread_cleanup_push because it is one of the few pthread\r
+ # functions on Solaris that doesn't have a non-functional libc stub.\r
+ # We try pthread_create on general principles.\r
+ AC_TRY_LINK([#include <pthread.h>],\r
+ [pthread_t th; pthread_join(th, 0);\r
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);\r
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],\r
+ [acx_pthread_ok=yes])\r
+\r
+ LIBS="$save_LIBS"\r
+ CFLAGS="$save_CFLAGS"\r
+\r
+ AC_MSG_RESULT($acx_pthread_ok)\r
+ if test "x$acx_pthread_ok" = xyes; then\r
+ break;\r
+ fi\r
+\r
+ PTHREAD_LIBS=""\r
+ PTHREAD_CFLAGS=""\r
+done\r
+fi\r
+\r
+# Various other checks:\r
+if test "x$acx_pthread_ok" = xyes; then\r
+ save_LIBS="$LIBS"\r
+ LIBS="$PTHREAD_LIBS $LIBS"\r
+ save_CFLAGS="$CFLAGS"\r
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"\r
+\r
+ # Detect AIX lossage: threads are created detached by default\r
+ # and the JOINABLE attribute has a nonstandard name (UNDETACHED).\r
+ AC_MSG_CHECKING([for joinable pthread attribute])\r
+ AC_TRY_LINK([#include <pthread.h>],\r
+ [int attr=PTHREAD_CREATE_JOINABLE;],\r
+ ok=PTHREAD_CREATE_JOINABLE, ok=unknown)\r
+ if test x"$ok" = xunknown; then\r
+ AC_TRY_LINK([#include <pthread.h>],\r
+ [int attr=PTHREAD_CREATE_UNDETACHED;],\r
+ ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)\r
+ fi\r
+ if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then\r
+ AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,\r
+ [Define to the necessary symbol if this constant\r
+ uses a non-standard name on your system.])\r
+ fi\r
+ AC_MSG_RESULT(${ok})\r
+ if test x"$ok" = xunknown; then\r
+ AC_MSG_WARN([we do not know how to create joinable pthreads])\r
+ fi\r
+\r
+ AC_MSG_CHECKING([if more special flags are required for pthreads])\r
+ flag=no\r
+ case "${host_cpu}-${host_os}" in\r
+ *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;\r
+ *-osf* | *-hpux*) flag="-D_REENTRANT";;\r
+ *solaris*)\r
+ if test "$GCC" = "yes"; then\r
+ flag="-D_REENTRANT"\r
+ else\r
+ flag="-mt -D_REENTRANT"\r
+ fi\r
+ ;;\r
+ esac\r
+ AC_MSG_RESULT(${flag})\r
+ if test "x$flag" != xno; then\r
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"\r
+ fi\r
+\r
+ LIBS="$save_LIBS"\r
+ CFLAGS="$save_CFLAGS"\r
+\r
+ # More AIX lossage: must compile with cc_r\r
+ AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})\r
+else\r
+ PTHREAD_CC="$CC"\r
+fi\r
+\r
+AC_SUBST(PTHREAD_LIBS)\r
+AC_SUBST(PTHREAD_CFLAGS)\r
+AC_SUBST(PTHREAD_CC)\r
+\r
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:\r
+if test x"$acx_pthread_ok" = xyes; then\r
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])\r
+ :\r
+else\r
+ acx_pthread_ok=no\r
+ $2\r
+fi\r
+AC_LANG_RESTORE\r
+])dnl ACX_PTHREAD\r
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
-AC_LANG(C++)
-
-# C++ requirements
-AC_CXX_REQUIRE_STL
-AC_CXX_NAMESPACES
-
-AC_LANG(C)
-
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_SIZE_T
AC_CHECK_HEADERS([dlfcn.h])
AC_CHECK_FUNC(dlclose, , [ AC_CHECK_LIB(dl, dlopen) ])
+# checks for pthreads
+ACX_PTHREAD([enable_threads="pthread"],[enable_threads="no"])
+if test $enable_threads != "pthread"; then
+ AC_MSG_ERROR([unable to find pthreads, currently this is required])
+else
+ AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.])
+ AM_CONDITIONAL(BUILD_PTHREAD,test "$enable_threads" = "pthread")
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
+ CXXFLAGS="$PTHREAD_CFLAGS $CXXFLAGS"
+fi
+
AC_LANG(C++)
+# C++ requirements
+AC_CXX_REQUIRE_STL
+AC_CXX_NAMESPACES
+
# log4cpp settings
AC_PATH_PROG(LOG4CPP_CONFIG,log4cpp-config)
AC_ARG_WITH(log4cpp,
util/DateTime.h \
util/NDC.h \
util/ParserPool.h \
+ util/Threads.h \
util/XMLConstants.h \
util/XMLHelper.h \
util/XMLObjectChildrenList.h
xmlsec_sources =
endif
+if BUILD_PTHREAD
+thread_sources = PThread.cpp
+else
+thread_sources =
+endif
+
libxmltooling_la_SOURCES = \
AbstractAttributeExtensibleXMLObject.cpp \
AbstractChildlessElement.cpp \
util/XMLHelper.cpp \
validation/AbstractValidatingXMLObject.cpp \
validation/Validator.cpp \
- ${xmlsec_sources}
+ ${xmlsec_sources} \
+ $(thread_sources)
# this is different from the project version
# http://sources.redhat.com/autobook/autobook/autobook_91.html
--- /dev/null
+/*\r
+ * Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * PThreads.cpp\r
+ * \r
+ * Thread and locking wrappers for POSIX platforms\r
+ */\r
+\r
+#include "internal.h"\r
+#include "util/Threads.h"\r
+\r
+#include <ctime>\r
+#include <log4cpp/Category.hh>\r
+\r
+#ifdef HAVE_PTHREAD\r
+# include <pthread.h>\r
+# ifndef HAVE_PTHREAD_RWLOCK_INIT\r
+# include <synch.h>\r
+# endif\r
+#else\r
+# error "This implementation is for POSIX platforms."\r
+#endif\r
+\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+\r
+namespace xmltooling {\r
+\r
+ class XMLTOOL_DLLLOCAL ThreadImpl : public Thread {\r
+ pthread_t thread_id;\r
+ public:\r
+ ThreadImpl(void* (*start_routine)(void*), void* arg);\r
+ virtual ~ThreadImpl() {}\r
+ \r
+ int detach() {\r
+ return pthread_detach(thread_id);\r
+ }\r
+ \r
+ int join(void** thread_return) {\r
+ return pthread_join(thread_id, thread_return);\r
+ }\r
+ \r
+ int kill(int signo) {\r
+ return pthread_kill(thread_id, signo);\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL MutexImpl : public Mutex {\r
+ pthread_mutex_t mutex;\r
+ public:\r
+ MutexImpl();\r
+ virtual ~MutexImpl() {\r
+ pthread_mutex_destroy(&mutex);\r
+ }\r
+ \r
+ int lock() {\r
+ return pthread_mutex_lock(&mutex);\r
+ }\r
+ \r
+ int unlock() {\r
+ return pthread_mutex_unlock(&mutex);\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait {\r
+ pthread_cond_t cond;\r
+ public:\r
+ CondWaitImpl();\r
+ virtual ~CondWaitImpl() {\r
+ pthread_cond_destroy(&cond);\r
+ }\r
+ \r
+ int wait(Mutex* mutex) {\r
+ return wait(static_cast<MutexImpl*>(mutex));\r
+ }\r
+ \r
+ int wait(MutexImpl* mutex) {\r
+ return pthread_cond_wait(&cond, &(mutex->mutex));\r
+ }\r
+ \r
+ int timedwait(Mutex* mutex, int delay_seconds) {\r
+ return timedwait(static_cast<MutexImpl*>(mutex), delay_seconds);\r
+ }\r
+ \r
+ int timedwait(MutexImpl* mutex, int delay_seconds) {\r
+ struct timespec ts;\r
+ memset(&ts, 0, sizeof(ts));\r
+ ts.tv_sec = time(NULL) + delay_seconds;\r
+ return pthread_cond_timedwait(&cond, &(mutex->mutex), &ts);\r
+ }\r
+ \r
+ int signal() {\r
+ return pthread_cond_signal(&cond);\r
+ }\r
+ \r
+ int broadcast() {\r
+ return pthread_cond_broadcast(&cond);\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock {\r
+#ifdef HAVE_PTHREAD_RWLOCK_INIT\r
+ pthread_rwlock_t lock;\r
+ public:\r
+ RWLockImpl();\r
+ virtual ~RWLockImpl() {\r
+ pthread_rwlock_destroy(&lock);\r
+ }\r
+ \r
+ int rdlock() {\r
+ return pthread_rwlock_rdlock(&lock);\r
+ }\r
+ \r
+ int wrlock() {\r
+ return pthread_rwlock_wrlock(&lock);\r
+ }\r
+ \r
+ int unlock() {\r
+ return pthread_rwlock_unlock(&lock);\r
+ }\r
+#else\r
+ rwlock_t lock;\r
+ public:\r
+ RWLockImpl();\r
+ virtual ~RWLockImpl() {\r
+ rwlock_destroy (&lock);\r
+ }\r
+ \r
+ int rdlock() {\r
+ return rw_rdlock(&lock);\r
+ }\r
+ \r
+ int wrlock() {\r
+ return rw_wrlock(&lock);\r
+ }\r
+ \r
+ int unlock() {\r
+ return rw_unlock(&lock);\r
+ }\r
+#endif\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {\r
+ pthread_key_t key;\r
+ public:\r
+ ThreadKeyImpl(void (*destroy_fcn)(void*));\r
+ virtual ~ThreadKeyImpl() {\r
+ pthread_key_delete(key);\r
+ }\r
+ \r
+ int setData(void* data) {\r
+ return pthread_setspecific(key,data);\r
+ }\r
+ \r
+ void* getData() const {\r
+ return pthread_getspecific(key);\r
+ }\r
+ };\r
+\r
+};\r
+\r
+ThreadImpl::ThreadImpl(void* (*start_routine)(void*), void* arg)\r
+{\r
+ int rc=pthread_create(&thread_id, NULL, start_routine, arg);\r
+ if (rc) {\r
+#ifdef HAVE_STRERROR_R\r
+ char buf[256];\r
+ strerror_r(rc,buf,sizeof(buf));\r
+ buf[255]=0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,buf);\r
+#else\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,strerror(rc));\r
+#endif\r
+ throw ThreadingException("Thread creation failed.");\r
+ }\r
+}\r
+\r
+MutexImpl::MutexImpl()\r
+{\r
+ int rc=pthread_mutex_init(&mutex, NULL);\r
+ if (rc) {\r
+#ifdef HAVE_STRERROR_R\r
+ char buf[256];\r
+ strerror_r(rc,buf,sizeof(buf));\r
+ buf[255]=0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,buf);\r
+#else\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc));\r
+#endif\r
+ throw ThreadingException("Mutex creation failed.");\r
+ }\r
+}\r
+\r
+CondWaitImpl::CondWaitImpl()\r
+{\r
+ int rc=pthread_cond_init(&cond, NULL);\r
+ if (rc) {\r
+#ifdef HAVE_STRERROR_R\r
+ char buf[256];\r
+ strerror_r(rc,buf,sizeof(buf));\r
+ buf[255]=0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,buf);\r
+#else\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc));\r
+#endif\r
+ throw ThreadingException("Condition variable creation failed.");\r
+ }\r
+}\r
+\r
+RWLockImpl::RWLockImpl()\r
+{\r
+#ifdef HAVE_PTHREAD_RWLOCK_INIT\r
+ int rc=pthread_rwlock_init(&lock, NULL);\r
+#else\r
+ int rc=rwlock_init(&lock, USYNC_THREAD, NULL);\r
+#endif\r
+ if (rc) {\r
+#ifdef HAVE_STRERROR_R\r
+ char buf[256];\r
+ strerror_r(rc,buf,sizeof(buf));\r
+ buf[255]=0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,buf);\r
+#else\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc));\r
+#endif\r
+ throw ThreadingException("Shared lock creation failed.");\r
+ }\r
+}\r
+\r
+ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*))\r
+{\r
+ int rc=pthread_key_create(&key, destroy_fcn);\r
+ if (rc) {\r
+#ifdef HAVE_STRERROR_R\r
+ char buf[256];\r
+ strerror_r(rc,buf,sizeof(buf));\r
+ buf[255]=0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,buf);\r
+#else\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,strerror(rc));\r
+#endif\r
+ throw ThreadingException("Thread key creation failed.");\r
+ }\r
+}\r
+\r
+Thread* Thread::create(void* (*start_routine)(void*), void* arg)\r
+{\r
+ return new ThreadImpl(start_routine, arg);\r
+}\r
+\r
+void Thread::exit(void* return_val)\r
+{\r
+ pthread_exit(return_val);\r
+}\r
+ \r
+void Thread::mask_all_signals(void)\r
+{\r
+ sigset_t sigmask;\r
+ sigfillset(&sigmask);\r
+ Thread::mask_signals(SIG_BLOCK, &sigmask, NULL);\r
+}\r
+\r
+int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask)\r
+{\r
+ return pthread_sigmask(how,newmask,oldmask);\r
+}\r
+\r
+Mutex * Mutex::create()\r
+{\r
+ return new MutexImpl();\r
+}\r
+\r
+CondWait * CondWait::create()\r
+{\r
+ return new CondWaitImpl();\r
+}\r
+\r
+RWLock * RWLock::create()\r
+{\r
+ return new RWLockImpl();\r
+}\r
+\r
+ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))\r
+{\r
+ return new ThreadKeyImpl(destroy_fcn);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file Threads.h\r
+ * \r
+ * Thread and locking wrappers \r
+ */\r
+\r
+#ifndef _xmltooling_threads_h\r
+#define _xmltooling_threads_h\r
+\r
+#include <xmltooling/base.h>\r
+#include <xmltooling/exceptions.h>\r
+\r
+namespace xmltooling\r
+{\r
+ DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations);\r
+ \r
+ /**\r
+ * A class for manual thread creation and synchronization.\r
+ */\r
+ class XMLTOOL_API Thread\r
+ {\r
+ MAKE_NONCOPYABLE(Thread);\r
+ public:\r
+ Thread() {}\r
+ virtual ~Thread() {}\r
+\r
+ /**\r
+ * Disassociate from the thread.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int detach()=0;\r
+ \r
+ /**\r
+ * Join with the thread and wait for its completion.\r
+ * \r
+ * @param thread_return holds the return value of the thread routine\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int join(void** thread_return)=0;\r
+ \r
+ /**\r
+ * Kill the thread.\r
+ * \r
+ * @param signo the signal to send to the thread\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int kill(int signo)=0;\r
+ \r
+ /**\r
+ * Creates a new thread object to run the supplied start routine.\r
+ * \r
+ * @param start_routine the function to execute on the thread\r
+ * @param arg a parameter for the start routine\r
+ * @return the created and running thread object \r
+ */\r
+ static Thread* create(void* (*start_routine)(void*), void* arg);\r
+ \r
+ /**\r
+ * Exits a thread gracefully.\r
+ * \r
+ * @param return_val the return value for the thread\r
+ */\r
+ static void exit(void* return_val);\r
+ \r
+#ifndef WIN32\r
+ /**\r
+ * Masks all signals from a thread. \r
+ */\r
+ static void mask_all_signals(void);\r
+ \r
+ /**\r
+ * Masks specific signals from a thread.\r
+ * \r
+ * @param how\r
+ * @param newmask the new signal mask\r
+ * @param oldmask the old signal mask\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ static int mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask);\r
+#endif\r
+ };\r
+\r
+ /**\r
+ * A class for managing Thread Local Storage values.\r
+ */\r
+ class XMLTOOL_API ThreadKey\r
+ {\r
+ MAKE_NONCOPYABLE(ThreadKey);\r
+ public:\r
+ ThreadKey() {}\r
+ virtual ~ThreadKey() {}\r
+\r
+ /**\r
+ * Sets the value for a TLS key.\r
+ * \r
+ * @param data the value to set\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int setData(void* data)=0;\r
+\r
+ /**\r
+ * Returns the value for a TLS key.\r
+ * \r
+ * @return the value or NULL\r
+ */ \r
+ virtual void* getData() const=0;\r
+\r
+ /**\r
+ * Creates a new TLS key.\r
+ * \r
+ * @param destroy_fn a functon to cleanup key values\r
+ * @return the new key\r
+ */\r
+ static ThreadKey* create(void (*destroy_fn)(void*));\r
+ };\r
+\r
+ /**\r
+ * A class for managing exclusive access to resources.\r
+ */\r
+ class XMLTOOL_API Mutex\r
+ {\r
+ MAKE_NONCOPYABLE(Mutex);\r
+ public:\r
+ Mutex() {}\r
+ virtual ~Mutex() {}\r
+\r
+ /**\r
+ * Locks the mutex for exclusive access.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int lock()=0;\r
+ \r
+ /**\r
+ * Unlocks the mutex for exclusive access.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int unlock()=0;\r
+\r
+ /**\r
+ * Creates a new mutex object.\r
+ * \r
+ * @return the new mutex\r
+ */\r
+ static Mutex* create();\r
+ };\r
+ \r
+ /**\r
+ * A class for managing shared and exclusive access to resources.\r
+ */\r
+ class XMLTOOL_API RWLock\r
+ {\r
+ MAKE_NONCOPYABLE(RWLock);\r
+ public:\r
+ RWLock() {}\r
+ virtual ~RWLock() {}\r
+\r
+ /**\r
+ * Obtains a shared lock.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int rdlock()=0;\r
+ \r
+ /**\r
+ * Obtains an exclusive lock.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int wrlock()=0;\r
+\r
+ /**\r
+ * Unlocks the lock.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int unlock()=0;\r
+\r
+ /**\r
+ * Creates a new read/write lock.\r
+ * \r
+ * @return the new lock\r
+ */\r
+ static RWLock* create();\r
+ };\r
+ \r
+ /**\r
+ * A class for establishing queues on a mutex based on a periodic condition.\r
+ */\r
+ class XMLTOOL_API CondWait\r
+ {\r
+ MAKE_NONCOPYABLE(CondWait);\r
+ public:\r
+ CondWait() {}\r
+ virtual ~CondWait() {}\r
+ \r
+ /**\r
+ * Waits for a condition variable using the supplied mutex as a queue.\r
+ * \r
+ * @param lock mutex to queue on\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int wait(Mutex* lock)=0;\r
+ \r
+ /**\r
+ * Waits for a condition variable using the supplied mutex as a queue,\r
+ * but only for a certain time limit.\r
+ * \r
+ * @param lock mutex to queue on\r
+ * @param delay_seconds maximum time to wait before waking up\r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int timedwait(Mutex* lock, int delay_seconds)=0;\r
+ \r
+ /**\r
+ * Signal a single thread to wake up if a condition changes.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int signal()=0;\r
+ \r
+ /**\r
+ * Signal all threads to wake up if a condition changes.\r
+ * \r
+ * @return 0 for success, non-zero for failure\r
+ */\r
+ virtual int broadcast()=0;\r
+\r
+ /**\r
+ * Creates a new condition variable.\r
+ * \r
+ * @return the new condition variable\r
+ */\r
+ static CondWait* create();\r
+ };\r
+ \r
+ /**\r
+ * RAII wrapper for a mutex lock.\r
+ */\r
+ class XMLTOOL_API Lock {\r
+ MAKE_NONCOPYABLE(Lock);\r
+ public:\r
+ /**\r
+ * Locks and wraps the designated mutex.\r
+ * \r
+ * @param mtx mutex to lock \r
+ */\r
+ Lock(Mutex* mtx) : mutex(mtx) {\r
+ mutex->lock();\r
+ }\r
+ \r
+ /**\r
+ * Unlocks the wrapped mutex.\r
+ */\r
+ ~Lock() {\r
+ mutex->unlock();\r
+ }\r
+ \r
+ private:\r
+ Mutex* mutex;\r
+ };\r
+ \r
+ /**\r
+ * RAII wrapper for a shared lock.\r
+ */\r
+ class XMLTOOL_API ReadLock {\r
+ MAKE_NONCOPYABLE(ReadLock);\r
+ public:\r
+ /**\r
+ * Locks and wraps the designated shared lock.\r
+ * \r
+ * @param lock lock to acquire \r
+ */\r
+ ReadLock(RWLock* lock) : rwlock(lock) {\r
+ rwlock->rdlock();\r
+ }\r
+ \r
+ /**\r
+ * Unlocks the wrapped shared lock.\r
+ */\r
+ ~ReadLock() {\r
+ rwlock->unlock();\r
+ }\r
+ \r
+ private:\r
+ RWLock* rwlock;\r
+ };\r
+\r
+}\r
+\r
+#endif /* _xmltooling_threads_h */\r
--- /dev/null
+/*\r
+ * Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * Win32Threads.cpp\r
+ * \r
+ * Thread and locking wrappers for Win32 platforms\r
+ */\r
+\r
+#include "internal.h"\r
+#include "util/Threads.h"\r
+\r
+#include <log4cpp/Category.hh>\r
+\r
+#ifndef WIN32\r
+# error "This implementation is for WIN32 platforms."\r
+#endif\r
+\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+\r
+// base error code for a routine to return on failure\r
+#define THREAD_ERROR_TIMEOUT (1)\r
+#define THREAD_ERROR_WAKE_OTHER (2)\r
+#define THREAD_ERROR (3)\r
+\r
+// windows returns non zero for success pthreads returns zero\r
+static int XMLTOOL_DLLLOCAL map_windows_error_status_to_pthreads(int rc=0) {\r
+ if(rc!=0) // success?\r
+ return 0;\r
+ Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("error from thread operation (%d)", GetLastError());\r
+ return THREAD_ERROR;\r
+}\r
+\r
+namespace xmltooling {\r
+\r
+ // two levels of classes are needed here\r
+ // in case InitializeCriticalSection\r
+ // throws an exception we can keep from\r
+ // calling the critical_section destructor\r
+ // on unitilized data, or it could be done with a flag\r
+ struct XMLTOOL_DLLLOCAL critical_section_data {\r
+ CRITICAL_SECTION cs;\r
+ critical_section_data(){\r
+ InitializeCriticalSection(&cs); \r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL critical_section {\r
+ private:\r
+ critical_section_data cse;\r
+ public:\r
+ critical_section(){}\r
+ ~critical_section(){\r
+ DeleteCriticalSection (&cse.cs);\r
+ }\r
+ void enter(void) {\r
+ EnterCriticalSection(&cse.cs);\r
+ }\r
+ void leave(void) {\r
+ LeaveCriticalSection(&cse.cs);\r
+ }\r
+ };\r
+ \r
+ // hold a critical section over the lifetime of this object\r
+ // used to make a stack variable that unlocks automaticly\r
+ // on return/throw\r
+ class XMLTOOL_DLLLOCAL with_crit_section {\r
+ private:\r
+ critical_section& cs;\r
+ public:\r
+ with_crit_section(critical_section& acs):cs(acs){\r
+ cs.enter();\r
+ }\r
+ ~with_crit_section(){\r
+ cs.leave();\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL ThreadImpl : public Thread {\r
+ private:\r
+ HANDLE thread_id;\r
+ public:\r
+ ThreadImpl(void* (*start_routine)(void*), void* arg) : thread_id(0) {\r
+ thread_id=CreateThread(\r
+ 0, // security attributes\r
+ 0, // use default stack size, maybe this should be setable\r
+ (LPTHREAD_START_ROUTINE ) start_routine,\r
+ arg,\r
+ 0, // flags, default is ignore stacksize and don't create suspended which is what we want\r
+ 0);\r
+ if (thread_id==0) {\r
+ map_windows_error_status_to_pthreads();\r
+ throw ThreadingException("Thread creation failed.");\r
+ }\r
+ }\r
+\r
+ ~ThreadImpl() {\r
+ (void)detach();\r
+ }\r
+ \r
+ int detach() {\r
+ if (thread_id==0)\r
+ return THREAD_ERROR;\r
+ int rc=map_windows_error_status_to_pthreads(CloseHandle(thread_id));\r
+ thread_id=0;\r
+ return rc;\r
+ }\r
+\r
+ int join(void** thread_return) {\r
+ if (thread_id==0)\r
+ return THREAD_ERROR;\r
+ if (thread_return!=0)\r
+ *thread_return=0;\r
+ int rc=WaitForSingleObject(thread_id,INFINITE);\r
+ switch(rc) {\r
+ case WAIT_OBJECT_0:\r
+ if (thread_return)\r
+ map_windows_error_status_to_pthreads(GetExitCodeThread(thread_id,(unsigned long*)thread_return));\r
+ default:\r
+ return THREAD_ERROR;\r
+ }\r
+ return 0;\r
+ }\r
+ \r
+ int kill(int signo) {\r
+ if (thread_id==0)\r
+ return THREAD_ERROR;\r
+ return map_windows_error_status_to_pthreads(TerminateThread(thread_id,signo));\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL MutexImpl : public Mutex {\r
+ private:\r
+ HANDLE mhandle;\r
+ public:\r
+ MutexImpl() : mhandle(CreateMutex(0,false,0)) {\r
+ if (mhandle==0) {\r
+ map_windows_error_status_to_pthreads();\r
+ throw ThreadingException("Mutex creation failed.");\r
+ }\r
+ }\r
+ \r
+ ~MutexImpl() {\r
+ if((mhandle!=0) && (!CloseHandle(mhandle))) \r
+ map_windows_error_status_to_pthreads();\r
+ }\r
+ \r
+ int lock() {\r
+ int rc=WaitForSingleObject(mhandle,INFINITE);\r
+ switch(rc) {\r
+ case WAIT_ABANDONED:\r
+ case WAIT_OBJECT_0:\r
+ return 0;\r
+ default:\r
+ return map_windows_error_status_to_pthreads();\r
+ }\r
+ }\r
+ \r
+ int unlock() {\r
+ return map_windows_error_status_to_pthreads(ReleaseMutex(mhandle));\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait {\r
+ private:\r
+ HANDLE cond;\r
+ \r
+ public:\r
+ CondWaitImpl() : cond(CreateEvent(0,false,false,0)) {\r
+ if(cond==0) {\r
+ map_windows_error_status_to_pthreads();\r
+ throw ThreadingException("Event creation failed.");\r
+ }\r
+ };\r
+ \r
+ ~CondWaitImpl() {\r
+ if((cond!=0) && (!CloseHandle(cond))) \r
+ map_windows_error_status_to_pthreads();\r
+ }\r
+ \r
+ int wait(Mutex* mutex) {\r
+ return timedwait(mutex,INFINITE);\r
+ }\r
+ \r
+ int signal() {\r
+ if(!SetEvent(cond))\r
+ return map_windows_error_status_to_pthreads();\r
+ return 0;\r
+ }\r
+ \r
+ int broadcast() {\r
+ throw ThreadingException("Broadcast not implemented on Win32 platforms.");\r
+ }\r
+ \r
+ // wait for myself to signal and this mutex or the timeout\r
+ int timedwait(Mutex* mutex, int delay_seconds) {\r
+ int rc=mutex->unlock();\r
+ if(rc!=0)\r
+ return rc;\r
+ \r
+ int delay_ms=delay_seconds;\r
+ if(delay_seconds!=INFINITE)\r
+ delay_ms*=1000;\r
+ rc=WaitForSingleObject(cond,delay_ms);\r
+ int rc2=mutex->lock();\r
+ if(rc2!=0)\r
+ return rc2;\r
+ switch(rc) {\r
+ case WAIT_ABANDONED:\r
+ case WAIT_OBJECT_0:\r
+ case WAIT_TIMEOUT:\r
+ return 0;\r
+ default:\r
+ return map_windows_error_status_to_pthreads();\r
+ }\r
+ return 0;\r
+ }\r
+ };\r
+ \r
+ class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock {\r
+ private:\r
+ // used to protect read or write to the data below\r
+ critical_section cs;\r
+ // event handle threads wait on when the lock they want is busy\r
+ // normally set to signaled all the time, if some thread can't get what\r
+ // they want they reset it and sleep. on releasing a lock set it to\r
+ // signaled if someone may have wanted what you just released\r
+ HANDLE wake_waiters;\r
+ // number of threads holding a read lock\r
+ int num_readers;\r
+ // true iff there a writer has our lock\r
+ bool have_writer;\r
+ \r
+ public:\r
+ RWLockImpl() : wake_waiters(0), num_readers(0), have_writer(true) {\r
+ with_crit_section acs(cs);\r
+ wake_waiters=CreateEvent(0,true,true,0);\r
+ have_writer=false;\r
+ if (wake_waiters==0) {\r
+ map_windows_error_status_to_pthreads();\r
+ throw ThreadingException("Event creation for shared lock failed.");\r
+ }\r
+ }\r
+ \r
+ ~RWLockImpl() { \r
+ with_crit_section acs(cs);\r
+ if ((wake_waiters!=0) && (!CloseHandle(wake_waiters))) \r
+ map_windows_error_status_to_pthreads();\r
+ }\r
+ \r
+ int rdlock() {\r
+ while(1) {\r
+ // wait for the lock maybe being availible\r
+ // we will find out for sure inside the critical section\r
+ if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0) \r
+ return map_windows_error_status_to_pthreads();\r
+ \r
+ with_crit_section alock(cs);\r
+ // invariant not locked for reading and writing\r
+ if ((num_readers!=0) && (have_writer))\r
+ return THREAD_ERROR;\r
+ // if no writer we can join any existing readers\r
+ if (!have_writer) {\r
+ num_readers++;\r
+ return 0;\r
+ }\r
+ \r
+ // have a writer, mark the synchronization object\r
+ // so everyone waits, when the writer unlocks it will wake us\r
+ if (!ResetEvent(wake_waiters))\r
+ return map_windows_error_status_to_pthreads();\r
+ }\r
+ return THREAD_ERROR;\r
+ }\r
+ \r
+ int wrlock() {\r
+ while(1) {\r
+ // wait for the lock maybe being availible\r
+ // we will find out for sure inside the critical section\r
+ if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0) \r
+ return map_windows_error_status_to_pthreads();\r
+\r
+ with_crit_section bla(cs);\r
+ // invariant not locked for reading and writing\r
+ if ((num_readers!=0) && (have_writer))\r
+ return THREAD_ERROR;\r
+\r
+ // if no writer and no readers we can become the writer\r
+ if ((num_readers==0) && (!have_writer)) {\r
+ have_writer=true;\r
+ return 0;\r
+ }\r
+ \r
+ // lock is busy, the unlocker will wake us\r
+ if (!ResetEvent(wake_waiters))\r
+ return map_windows_error_status_to_pthreads();\r
+ }\r
+ return THREAD_ERROR;\r
+ }\r
+ \r
+ int unlock() {\r
+ with_crit_section mumble(cs);\r
+ // invariant not locked for reading and writing\r
+ if ((num_readers!=0) && (have_writer))\r
+ return THREAD_ERROR;\r
+ \r
+ // error if nothing locked\r
+ if ((num_readers==0) && (!have_writer))\r
+ return THREAD_ERROR;\r
+ \r
+ // if there was a writer it has to be us so unlock write lock \r
+ have_writer=false;\r
+ \r
+ // if there where any reades there is one less now\r
+ if(num_readers>0)\r
+ num_readers--;\r
+ \r
+ // if no readers left wake up any readers/writers waiting\r
+ // to have a go at it\r
+ if (num_readers==0)\r
+ if (!SetEvent(wake_waiters))\r
+ return map_windows_error_status_to_pthreads();\r
+ return 0;\r
+ }\r
+ };\r
+ \r
+ typedef void (*destroy_hook_type)(void*);\r
+ \r
+ class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {\r
+ private:\r
+ destroy_hook_type destroy_hook;\r
+ DWORD key;\r
+ \r
+ public:\r
+ ThreadKeyImpl(void (*destroy_fcn)(void*)) : destroy_hook(destroy_fcn) {\r
+ key=TlsAlloc();\r
+ };\r
+ \r
+ virtual ~ThreadKeyImpl() {\r
+ if (destroy_hook)\r
+ destroy_hook(TlsGetValue(key));\r
+ TlsFree(key);\r
+ }\r
+ \r
+ int setData(void* data) {\r
+ TlsSetValue(key,data);\r
+ return 0;\r
+ }\r
+ \r
+ void* getData() const {\r
+ return TlsGetValue(key);\r
+ }\r
+ };\r
+\r
+};\r
+\r
+//\r
+// public "static" creation functions\r
+//\r
+\r
+Thread* Thread::create(void* (*start_routine)(void*), void* arg)\r
+{\r
+ return new ThreadImpl(start_routine, arg);\r
+}\r
+\r
+void Thread::exit(void* return_val)\r
+{\r
+ ExitThread((DWORD)return_val);\r
+}\r
+\r
+Mutex * Mutex::create()\r
+{\r
+ return new MutexImpl();\r
+}\r
+\r
+CondWait * CondWait::create()\r
+{\r
+ return new CondWaitImpl();\r
+}\r
+\r
+RWLock * RWLock::create()\r
+{\r
+ return new RWLockImpl();\r
+}\r
+\r
+ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))\r
+{\r
+ return new ThreadKeyImpl(destroy_fcn);\r
+}\r
>\r
</File>\r
<File\r
+ RelativePath=".\util\Win32Threads.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\util\XMLConstants.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\util\Threads.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\util\XMLConstants.h"\r
>\r
</File>\r