gcc const fix, converted linefeeds
[shibboleth/cpp-xmltooling.git] / xmltooling / util / Win32Threads.cpp
index 8e5cdc0..1111f4d 100644 (file)
-/*\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
-void Thread::sleep(int seconds)\r
-{\r
-    Sleep(seconds * 1000);\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
+/*
+ *  Copyright 2001-2006 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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Win32Threads.cpp
+ * 
+ * Thread and locking wrappers for Win32 platforms
+ */
+
+#include "internal.h"
+#include "util/Threads.h"
+
+#include <log4cpp/Category.hh>
+
+#ifndef WIN32
+# error "This implementation is for WIN32 platforms."
+#endif
+
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+// base error code for a routine to return on failure
+#define THREAD_ERROR_TIMEOUT   (1)
+#define THREAD_ERROR_WAKE_OTHER (2)
+#define THREAD_ERROR               (3)
+
+// windows returns non zero for success pthreads returns zero
+static int XMLTOOL_DLLLOCAL map_windows_error_status_to_pthreads(int rc=0) {
+    if(rc!=0)  // success?
+        return 0;
+    Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("error from thread operation (%d)", GetLastError());
+    return THREAD_ERROR;
+}
+
+namespace xmltooling {
+
+    // two levels of classes are needed here
+    // in case InitializeCriticalSection
+    // throws an exception we can keep from
+    // calling the critical_section destructor
+    // on unitilized data, or it could be done with a flag
+    struct XMLTOOL_DLLLOCAL critical_section_data {
+        CRITICAL_SECTION cs;
+        critical_section_data(){
+            InitializeCriticalSection(&cs);    
+        }
+    };
+    
+    class XMLTOOL_DLLLOCAL critical_section {
+    private:
+        critical_section_data  cse;
+    public:
+        critical_section(){}
+        ~critical_section(){
+            DeleteCriticalSection (&cse.cs);
+        }
+        void enter(void) {
+            EnterCriticalSection(&cse.cs);
+        }
+        void leave(void) {
+            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
+    class XMLTOOL_DLLLOCAL with_crit_section {
+    private:
+        critical_section& cs;
+    public:
+        with_crit_section(critical_section& acs):cs(acs){
+            cs.enter();
+        }
+        ~with_crit_section(){
+            cs.leave();
+        }
+    };
+    
+    class XMLTOOL_DLLLOCAL ThreadImpl : public Thread {
+    private:
+        HANDLE thread_id;
+    public:
+        ThreadImpl(void* (*start_routine)(void*), void* arg) : thread_id(0) {
+            thread_id=CreateThread(
+                0, // security attributes
+                0, // use default stack size, maybe this should be setable
+                (LPTHREAD_START_ROUTINE ) start_routine,
+                arg,
+                0, // flags, default is ignore stacksize and don't create suspended which is what we want
+                0);
+            if (thread_id==0) {
+                map_windows_error_status_to_pthreads();
+                throw ThreadingException("Thread creation failed.");
+            }
+        }
+
+        ~ThreadImpl() {
+            (void)detach();
+        }
+    
+        int detach() {
+            if (thread_id==0)
+                return THREAD_ERROR;
+            int rc=map_windows_error_status_to_pthreads(CloseHandle(thread_id));
+            thread_id=0;
+            return rc;
+        }
+
+        int join(void** thread_return) {
+            if (thread_id==0)
+                return THREAD_ERROR;
+            if (thread_return!=0)
+                *thread_return=0;
+            int rc=WaitForSingleObject(thread_id,INFINITE);
+            switch(rc) {
+                case WAIT_OBJECT_0:
+                    if (thread_return)
+                        map_windows_error_status_to_pthreads(GetExitCodeThread(thread_id,(unsigned long*)thread_return));
+                default:
+                    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;
+    public:
+        MutexImpl() : mhandle(CreateMutex(0,false,0)) {
+            if (mhandle==0) {
+                map_windows_error_status_to_pthreads();
+                throw ThreadingException("Mutex creation failed.");
+            }
+        }
+        
+        ~MutexImpl() {
+            if((mhandle!=0) && (!CloseHandle(mhandle))) 
+                map_windows_error_status_to_pthreads();
+        }
+        
+        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();
+            }
+        }
+        
+        int unlock() {
+            return map_windows_error_status_to_pthreads(ReleaseMutex(mhandle));
+        }
+    };
+    
+    class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait {
+    private:
+        HANDLE cond;
+    
+    public:
+        CondWaitImpl() : cond(CreateEvent(0,false,false,0)) {
+            if(cond==0) {
+                map_windows_error_status_to_pthreads();
+               throw ThreadingException("Event creation failed.");
+            }
+        };
+    
+        ~CondWaitImpl() {
+            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;
+            rc=WaitForSingleObject(cond,delay_ms);
+            int rc2=mutex->lock();
+            if(rc2!=0)
+                return rc2;
+            switch(rc) {
+                case WAIT_ABANDONED:
+                case WAIT_OBJECT_0:
+                case WAIT_TIMEOUT:
+                    return 0;
+                default:
+                    return map_windows_error_status_to_pthreads();
+            }
+            return 0;
+        }
+    };
+    
+    class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock {
+    private:
+        // used to protect read or write to the data below
+        critical_section cs;
+        // event handle threads wait on when the lock they want is busy
+        // normally set to signaled all the time, if some thread can't get what
+        // they want they reset it and sleep.  on releasing a lock set it to
+        // signaled if someone may have wanted what you just released
+        HANDLE wake_waiters;
+        // number of threads holding a read lock
+        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);
+            wake_waiters=CreateEvent(0,true,true,0);
+            have_writer=false;
+            if (wake_waiters==0) {
+                map_windows_error_status_to_pthreads();
+                throw ThreadingException("Event creation for shared lock failed.");
+            }
+        }
+        
+        ~RWLockImpl() { 
+            with_crit_section acs(cs);
+            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) 
+                    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))
+                    return THREAD_ERROR;
+                // if no writer we can join any existing readers
+                if (!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 map_windows_error_status_to_pthreads();
+            }
+            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) 
+                    return map_windows_error_status_to_pthreads();
+
+                with_crit_section bla(cs);
+                // invariant not locked for reading and writing
+                if ((num_readers!=0) && (have_writer))
+                      return THREAD_ERROR;
+
+                // if no writer and no readers we can become the writer
+                if ((num_readers==0) && (!have_writer)) {
+                    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 
+            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)
+                if (!SetEvent(wake_waiters))
+                    return map_windows_error_status_to_pthreads();
+            return 0;
+        }
+    };
+    
+    typedef void (*destroy_hook_type)(void*);
+    
+    class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {
+    private:
+        destroy_hook_type destroy_hook;
+        DWORD key;
+    
+    public:
+        ThreadKeyImpl(void (*destroy_fcn)(void*)) : destroy_hook(destroy_fcn) {
+            key=TlsAlloc();
+        };
+        
+        virtual ~ThreadKeyImpl() {
+            if (destroy_hook)
+                destroy_hook(TlsGetValue(key));
+            TlsFree(key);
+        }
+    
+        int setData(void* data) {
+            TlsSetValue(key,data);
+            return 0;
+        }
+        
+        void* getData() const {
+            return TlsGetValue(key);
+        }
+    };
+
+};
+
+//
+// public "static" creation functions
+//
+
+Thread* Thread::create(void* (*start_routine)(void*), void* arg)
+{
+    return new ThreadImpl(start_routine, arg);
+}
+
+void Thread::exit(void* return_val)
+{
+    ExitThread((DWORD)return_val);
+}
+
+void Thread::sleep(int seconds)
+{
+    Sleep(seconds * 1000);
+}
+
+Mutex * Mutex::create()
+{
+    return new MutexImpl();
+}
+
+CondWait * CondWait::create()
+{
+    return new CondWaitImpl();
+}
+
+RWLock * RWLock::create()
+{
+    return new RWLockImpl();
+}
+
+ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))
+{
+    return new ThreadKeyImpl(destroy_fcn);
+}