Threading support.
authorScott Cantor <cantor.2@osu.edu>
Sun, 2 Jul 2006 02:31:21 +0000 (02:31 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 2 Jul 2006 02:31:21 +0000 (02:31 +0000)
Makefile.am
acx_pthread.m4 [new file with mode: 0644]
configure.ac
xmltooling/Makefile.am
xmltooling/util/PThreads.cpp [new file with mode: 0644]
xmltooling/util/Threads.h [new file with mode: 0644]
xmltooling/util/Win32Threads.cpp [new file with mode: 0644]
xmltooling/xmltooling.vcproj

index 2afd6ff..76dd4cf 100644 (file)
@@ -10,6 +10,8 @@ EXTRA_DIST = $(DX_CONFIG) \
        doc \
        schemas \
        cpp-xmltooling.sln \
+       acx_pthread.m4 \
+       acinclude.m4 \
        libtool.m4 \
        doxygen.m4 \
        depcomp \
diff --git a/acx_pthread.m4 b/acx_pthread.m4
new file mode 100644 (file)
index 0000000..ba6c09c
--- /dev/null
@@ -0,0 +1,232 @@
+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
index bcb59f9..cf3b09c 100644 (file)
@@ -47,14 +47,6 @@ fi
 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
@@ -64,8 +56,24 @@ AC_CHECK_FUNCS([strchr strdup strstr])
 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,
index 0e8cdfe..9681b81 100644 (file)
@@ -65,6 +65,7 @@ utilinclude_HEADERS = \
        util/DateTime.h \
        util/NDC.h \
        util/ParserPool.h \
+       util/Threads.h \
        util/XMLConstants.h \
        util/XMLHelper.h \
        util/XMLObjectChildrenList.h
@@ -87,6 +88,12 @@ else
 xmlsec_sources =
 endif
 
+if BUILD_PTHREAD
+thread_sources = PThread.cpp
+else
+thread_sources =
+endif
+
 libxmltooling_la_SOURCES = \
        AbstractAttributeExtensibleXMLObject.cpp \
        AbstractChildlessElement.cpp \
@@ -114,7 +121,8 @@ libxmltooling_la_SOURCES = \
        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
diff --git a/xmltooling/util/PThreads.cpp b/xmltooling/util/PThreads.cpp
new file mode 100644 (file)
index 0000000..0678e2e
--- /dev/null
@@ -0,0 +1,301 @@
+/*\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
diff --git a/xmltooling/util/Threads.h b/xmltooling/util/Threads.h
new file mode 100644 (file)
index 0000000..ef9231b
--- /dev/null
@@ -0,0 +1,309 @@
+/*\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
diff --git a/xmltooling/util/Win32Threads.cpp b/xmltooling/util/Win32Threads.cpp
new file mode 100644 (file)
index 0000000..e239a17
--- /dev/null
@@ -0,0 +1,404 @@
+/*\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
index 4bed022..34b78c8 100644 (file)
                                        >\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