From ef331b0a0a5090d9e2ce53fb40835acea0764a7c Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Fri, 29 May 2009 17:02:33 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/CPPXT-30 --- xmltooling/XMLToolingConfig.cpp | 11 ++++ xmltooling/util/Threads.h | 120 +++++++++++++++++++++------------------ xmltooling/util/Win32Threads.cpp | 68 +++++++++++++--------- 3 files changed, 118 insertions(+), 81 deletions(-) diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index f4109fa..506e5be 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -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 diff --git a/xmltooling/util/Threads.h b/xmltooling/util/Threads.h index 40bd093..e3eee29 100644 --- a/xmltooling/util/Threads.h +++ b/xmltooling/util/Threads.h @@ -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 @@ -26,12 +26,12 @@ #include #include -#include +#include namespace xmltooling { DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations); - + /** * A class for manual thread creation and synchronization. */ @@ -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. + * + *

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; }; diff --git a/xmltooling/util/Win32Threads.cpp b/xmltooling/util/Win32Threads.cpp index 2613c80..072bb14 100644 --- a/xmltooling/util/Win32Threads.cpp +++ b/xmltooling/util/Win32Threads.cpp @@ -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 + #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 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::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(&ThreadKeyImpl::onDetach)); +} -- 2.1.4