/*
- * 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
/**
* @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.
*/
/**
* 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
/**
* Sets the value for a TLS key.
- *
+ *
* @param data the value to set
* @return 0 for success, non-zero for failure
*/
/**
* 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
};
/**
/**
* 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.
*/
/**
* 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.
*/
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.
*/
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.
*/
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;
};
/*
- * 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.
#include "logging.h"
#include "util/Threads.h"
+#include <algorithm>
+
#ifndef WIN32
# error "This implementation is for WIN32 platforms."
#endif
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;
}
};
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);
+ }
+ }
};
};
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));
+}