https://bugs.internet2.edu/jira/browse/CPPXT-30
authorcantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Fri, 29 May 2009 17:02:33 +0000 (17:02 +0000)
committercantor <cantor@de75baf8-a10c-0410-a50a-987c0e22f00f>
Fri, 29 May 2009 17:02:33 +0000 (17:02 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@590 de75baf8-a10c-0410-a50a-987c0e22f00f

xmltooling/XMLToolingConfig.cpp
xmltooling/util/Threads.h
xmltooling/util/Win32Threads.cpp

index f4109fa..506e5be 100644 (file)
@@ -529,3 +529,14 @@ void XMLToolingInternalConfig::registerXMLAlgorithms()
     registerXMLAlgorithm(DSIGConstants::s_unicodeStrURIKW_AES256, "AES", 256);
 }
 #endif
+
+#ifdef WIN32
+
+extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
+{
+    if (fdwReason == DLL_THREAD_DETACH)
+        ThreadKey::onDetach();
+    return TRUE;
+}
+
+#endif
index 40bd093..e3eee29 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  Copyright 2001-2007 Internet2
- * 
+ *  Copyright 2001-2009 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
@@ -16,8 +16,8 @@
 
 /**
  * @file xmltooling/util/Threads.h
- * 
- * Thread and locking wrappers 
+ *
+ * Thread and locking wrappers
  */
 
 #ifndef _xmltooling_threads_h
 #include <xmltooling/base.h>
 #include <xmltooling/exceptions.h>
 
-#include <signal.h>\r
+#include <signal.h>
 
 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.
      */
@@ -44,58 +44,58 @@ namespace xmltooling
 
         /**
          * 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 
+         * @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);
 
         /**
          * Sleeps the current thread for the specified amount of time.
-         * 
+         *
          * @param seconds   time to sleep
          */
-        static void sleep(int seconds);        
+        static void sleep(int seconds);
 #ifndef WIN32
         /**
-         * Masks all signals from a thread. 
+         * 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
@@ -117,7 +117,7 @@ namespace xmltooling
 
         /**
          * Sets the value for a TLS key.
-         * 
+         *
          * @param data  the value to set
          * @return 0 for success, non-zero for failure
          */
@@ -125,18 +125,28 @@ namespace xmltooling
 
         /**
          * 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*));
+
+#ifdef WIN32
+        /**
+         * Allows system to notify TLS implementation when a thread completes.
+         *
+         * <p>Windows doesn't support TLS destructors, so only the DllMain detach
+         * notification can be used to trigger per-thread cleanup.
+         */
+        static void onDetach();
+#endif
     };
 
     /**
@@ -151,26 +161,26 @@ namespace xmltooling
 
         /**
          * 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.
      */
@@ -183,33 +193,33 @@ namespace xmltooling
 
         /**
          * 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.
      */
@@ -219,47 +229,47 @@ namespace xmltooling
     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.
      */
@@ -268,24 +278,24 @@ namespace xmltooling
     public:
         /**
          * Locks and wraps the designated mutex.
-         * 
-         * @param mtx mutex to lock 
+         *
+         * @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.
      */
@@ -294,22 +304,22 @@ namespace xmltooling
     public:
         /**
          * Locks and wraps the designated shared lock.
-         * 
-         * @param lock      lock to acquire 
+         *
+         * @param lock      lock to acquire
          * @param lockit    true if the lock should be acquired here, false if already acquired
          */
         SharedLock(RWLock* lock, bool lockit=true) : rwlock(lock) {
             if (lockit)
                 rwlock->rdlock();
         }
-        
+
         /**
          * Unlocks the wrapped shared lock.
          */
         ~SharedLock() {
             rwlock->unlock();
         }
-    
+
     private:
         RWLock* rwlock;
     };
index 2613c80..072bb14 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2007 Internet2
+ *  Copyright 2001-2009 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
 #include "logging.h"
 #include "util/Threads.h"
 
+#include <algorithm>
+
 #ifndef WIN32
 # error "This implementation is for WIN32 platforms."
 #endif
@@ -145,33 +147,24 @@ namespace xmltooling {
 
     class XMLTOOL_DLLLOCAL MutexImpl : public Mutex {
     private:
-        HANDLE mhandle;
+        CRITICAL_SECTION mhandle;
     public:
-        MutexImpl() : mhandle(CreateMutex(0,false,0)) {
-            if (mhandle==0) {
-                map_windows_error_status_to_pthreads();
-                throw ThreadingException("Mutex creation failed.");
-            }
+        MutexImpl() {
+            InitializeCriticalSection(&mhandle);
         }
 
         ~MutexImpl() {
-            if((mhandle!=0) && (!CloseHandle(mhandle)))
-                map_windows_error_status_to_pthreads();
+            DeleteCriticalSection(&mhandle);
         }
 
         int lock() {
-            int rc=WaitForSingleObject(mhandle,INFINITE);
-            switch(rc) {
-                case WAIT_ABANDONED:
-                case WAIT_OBJECT_0:
-                    return 0;
-                default:
-                    return map_windows_error_status_to_pthreads();
-            }
+            EnterCriticalSection(&mhandle);
+            return 0;
         }
 
         int unlock() {
-            return map_windows_error_status_to_pthreads(ReleaseMutex(mhandle));
+            LeaveCriticalSection(&mhandle);
+            return 0;
         }
     };
 
@@ -342,30 +335,44 @@ namespace xmltooling {
 
     class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {
     private:
-        //destroy_hook_type destroy_hook;
+        destroy_hook_type destroy_hook;
         DWORD key;
-
+        static critical_section cs;
+        static set<ThreadKeyImpl*> m_keys;
+        friend class ThreadKey;
     public:
-        ThreadKeyImpl(void (*destroy_fcn)(void*)) { // : destroy_hook(destroy_fcn) {
-            if (destroy_fcn)
-                throw ThreadingException("TLS destructor function not supported.");
+        ThreadKeyImpl(void (*destroy_fcn)(void*)) : destroy_hook(destroy_fcn) {
             key=TlsAlloc();
+            if (destroy_fcn) {
+                with_crit_section wcs(cs);
+                m_keys.insert(this);
+            }
         };
 
         virtual ~ThreadKeyImpl() {
-            //if (destroy_hook)
-            //    destroy_hook(TlsGetValue(key));
+            if (destroy_hook) {
+                destroy_hook(TlsGetValue(key));
+                with_crit_section wcs(cs);
+                m_keys.erase(this);
+            }
             TlsFree(key);
         }
 
         int setData(void* data) {
-            TlsSetValue(key,data);
+            TlsSetValue(key, data);
             return 0;
         }
 
         void* getData() const {
             return TlsGetValue(key);
         }
+
+        void onDetach() const {
+            if (destroy_hook) {
+                destroy_hook(TlsGetValue(key));
+                TlsSetValue(key, NULL);
+            }
+        }
     };
 
 };
@@ -404,7 +411,16 @@ RWLock * RWLock::create()
     return new RWLockImpl();
 }
 
+critical_section ThreadKeyImpl::cs;
+set<ThreadKeyImpl*> ThreadKeyImpl::m_keys;
+
 ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))
 {
     return new ThreadKeyImpl(destroy_fcn);
 }
+
+void ThreadKey::onDetach()
+{
+    with_crit_section wcs(ThreadKeyImpl::cs);
+    for_each(ThreadKeyImpl::m_keys.begin(), ThreadKeyImpl::m_keys.end(), mem_fun<void,ThreadKeyImpl>(&ThreadKeyImpl::onDetach));
+}