/*
- * Copyright 2001-2007 Internet2
- *
+ * Copyright 2001-2010 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
/**
* Win32Threads.cpp
- *
- * Thread and locking wrappers for Win32 platforms
+ *
+ * Thread and locking wrappers for Win32 platforms.
*/
#include "internal.h"
+#include "logging.h"
#include "util/Threads.h"
-#include <log4cpp/Category.hh>
+#include <algorithm>
#ifndef WIN32
# error "This implementation is for WIN32 platforms."
#endif
+using namespace xmltooling::logging;
using namespace xmltooling;
-using namespace log4cpp;
using namespace std;
// base error code for a routine to return on failure
struct XMLTOOL_DLLLOCAL critical_section_data {
CRITICAL_SECTION cs;
critical_section_data(){
- InitializeCriticalSection(&cs);
+ InitializeCriticalSection(&cs);
}
};
-
+
class XMLTOOL_DLLLOCAL critical_section {
private:
critical_section_data cse;
LeaveCriticalSection(&cse.cs);
}
};
-
+
// hold a critical section over the lifetime of this object
// used to make a stack variable that unlocks automaticly
// on return/throw
cs.leave();
}
};
-
+
class XMLTOOL_DLLLOCAL ThreadImpl : public Thread {
private:
HANDLE thread_id;
public:
- ThreadImpl(void* (*start_routine)(void*), void* arg) : thread_id(0) {
+ ThreadImpl(void* (*start_routine)(void*), void* arg, size_t stacksize) : thread_id(0) {
thread_id=CreateThread(
0, // security attributes
- 0, // use default stack size, maybe this should be setable
+ stacksize, // 0 just means the default size anyway
(LPTHREAD_START_ROUTINE ) start_routine,
arg,
- 0, // flags, default is ignore stacksize and don't create suspended which is what we want
+ 0, // flags, default is don't create suspended which is what we want
0);
if (thread_id==0) {
map_windows_error_status_to_pthreads();
~ThreadImpl() {
(void)detach();
}
-
+
int detach() {
if (thread_id==0)
return THREAD_ERROR;
}
return 0;
}
-
+
int kill(int signo) {
if (thread_id==0)
return THREAD_ERROR;
return map_windows_error_status_to_pthreads(TerminateThread(thread_id,signo));
}
};
-
+
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 CondWaitImpl : public CondWait {
private:
HANDLE cond;
-
+
public:
CondWaitImpl() : cond(CreateEvent(0,false,false,0)) {
if(cond==0) {
throw ThreadingException("Event creation failed.");
}
};
-
+
~CondWaitImpl() {
- if((cond!=0) && (!CloseHandle(cond)))
+ if((cond!=0) && (!CloseHandle(cond)))
map_windows_error_status_to_pthreads();
}
-
+
int wait(Mutex* mutex) {
return timedwait(mutex,INFINITE);
}
-
+
int signal() {
if(!SetEvent(cond))
return map_windows_error_status_to_pthreads();
return 0;
}
-
+
int broadcast() {
throw ThreadingException("Broadcast not implemented on Win32 platforms.");
}
-
+
// wait for myself to signal and this mutex or the timeout
int timedwait(Mutex* mutex, int delay_seconds) {
int rc=mutex->unlock();
if(rc!=0)
return rc;
-
+
int delay_ms=delay_seconds;
if(delay_seconds!=INFINITE)
delay_ms*=1000;
return 0;
}
};
-
+
class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock {
private:
// used to protect read or write to the data below
int num_readers;
// true iff there a writer has our lock
bool have_writer;
-
+
public:
RWLockImpl() : wake_waiters(0), num_readers(0), have_writer(true) {
with_crit_section acs(cs);
throw ThreadingException("Event creation for shared lock failed.");
}
}
-
- ~RWLockImpl() {
+
+ ~RWLockImpl() {
with_crit_section acs(cs);
- if ((wake_waiters!=0) && (!CloseHandle(wake_waiters)))
+ if ((wake_waiters!=0) && (!CloseHandle(wake_waiters)))
map_windows_error_status_to_pthreads();
}
-
+
int rdlock() {
while(1) {
// wait for the lock maybe being availible
// we will find out for sure inside the critical section
- if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0)
+ if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0)
return map_windows_error_status_to_pthreads();
-
+
with_crit_section alock(cs);
// invariant not locked for reading and writing
if ((num_readers!=0) && (have_writer))
num_readers++;
return 0;
}
-
+
// have a writer, mark the synchronization object
// so everyone waits, when the writer unlocks it will wake us
if (!ResetEvent(wake_waiters))
}
return THREAD_ERROR;
}
-
+
int wrlock() {
while(1) {
// wait for the lock maybe being availible
// we will find out for sure inside the critical section
- if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0)
+ if (WaitForSingleObject(wake_waiters,INFINITE)!=WAIT_OBJECT_0)
return map_windows_error_status_to_pthreads();
with_crit_section bla(cs);
have_writer=true;
return 0;
}
-
+
// lock is busy, the unlocker will wake us
if (!ResetEvent(wake_waiters))
return map_windows_error_status_to_pthreads();
}
return THREAD_ERROR;
}
-
+
int unlock() {
with_crit_section mumble(cs);
// invariant not locked for reading and writing
if ((num_readers!=0) && (have_writer))
return THREAD_ERROR;
-
+
// error if nothing locked
if ((num_readers==0) && (!have_writer))
return THREAD_ERROR;
-
- // if there was a writer it has to be us so unlock write lock
+
+ // if there was a writer it has to be us so unlock write lock
have_writer=false;
-
+
// if there where any reades there is one less now
if(num_readers>0)
num_readers--;
-
+
// if no readers left wake up any readers/writers waiting
// to have a go at it
if (num_readers==0)
return 0;
}
};
-
+
typedef void (*destroy_hook_type)(void*);
-
+
class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {
private:
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) {
key=TlsAlloc();
+ if (destroy_fcn) {
+ with_crit_section wcs(cs);
+ m_keys.insert(this);
+ }
};
-
+
virtual ~ThreadKeyImpl() {
- if (destroy_hook)
+ 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, nullptr);
+ }
+ }
};
};
// public "static" creation functions
//
-Thread* Thread::create(void* (*start_routine)(void*), void* arg)
+Thread* Thread::create(void* (*start_routine)(void*), void* arg, size_t stacksize)
{
- return new ThreadImpl(start_routine, arg);
+ return new ThreadImpl(start_routine, arg, stacksize);
}
void Thread::exit(void* return_val)
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));
+}