2007-12-17 Brent Fulgham <bfulgham@gmail.com>
authoralp@webkit.org <alp@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2007 21:37:00 +0000 (21:37 +0000)
committeralp@webkit.org <alp@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 18 Dec 2007 21:37:00 +0000 (21:37 +0000)
        Reviewed by Darin.

        http://bugs.webkit.org/show_bug.cgi?id=16464
        Modify WebCore to use win32 thread primitives

        Updates to support native windows threading primitives
        rather than pthreads emulation library.

        * WebCore.vcproj/WebCore.vcproj:
        * config.h:
        * platform/Threading.h:
        * platform/win/MutexWin.cpp: Added.
        (WebCore::Mutex::Mutex):
        (WebCore::Mutex::~Mutex):
        (WebCore::Mutex::lock):
        (WebCore::Mutex::tryLock):
        (WebCore::Mutex::unlock):
        * platform/win/ThreadConditionWin.cpp: Added.
        (WebCore::ThreadCondition::ThreadCondition):
        (WebCore::ThreadCondition::~ThreadCondition):
        (WebCore::ThreadCondition::wait):
        (WebCore::ThreadCondition::signal):
        (WebCore::ThreadCondition::broadcast):
        * platform/win/ThreadingWin.cpp:
        (WebCore::threadMapMutex):
        (WebCore::threadMap):
        (WebCore::storeThreadHandleByIdentifier):
        (WebCore::identifierByThreadHandle):
        (WebCore::threadHandleForIdentifier):
        (WebCore::clearThreadHandleForIdentifier):
        (WebCore::createThread):
        (WebCore::waitForThreadCompletion):
        (WebCore::detachThread):
        (WebCore::currentThread):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28835 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/config.h
WebCore/platform/Threading.h
WebCore/platform/win/MutexWin.cpp [new file with mode: 0644]
WebCore/platform/win/ThreadConditionWin.cpp [new file with mode: 0644]
WebCore/platform/win/ThreadingWin.cpp

index 46e413814e7b51eddb3aa01e54b7d5b6b49ec070..e04030d74919ceb7dd979dce04b9fa8c21b66667 100644 (file)
@@ -1,3 +1,40 @@
+2007-12-17  Brent Fulgham  <bfulgham@gmail.com>
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=16464
+        Modify WebCore to use win32 thread primitives
+
+        Updates to support native windows threading primitives
+        rather than pthreads emulation library.
+
+        * WebCore.vcproj/WebCore.vcproj:
+        * config.h:
+        * platform/Threading.h:
+        * platform/win/MutexWin.cpp: Added.
+        (WebCore::Mutex::Mutex):
+        (WebCore::Mutex::~Mutex):
+        (WebCore::Mutex::lock):
+        (WebCore::Mutex::tryLock):
+        (WebCore::Mutex::unlock):
+        * platform/win/ThreadConditionWin.cpp: Added.
+        (WebCore::ThreadCondition::ThreadCondition):
+        (WebCore::ThreadCondition::~ThreadCondition):
+        (WebCore::ThreadCondition::wait):
+        (WebCore::ThreadCondition::signal):
+        (WebCore::ThreadCondition::broadcast):
+        * platform/win/ThreadingWin.cpp:
+        (WebCore::threadMapMutex):
+        (WebCore::threadMap):
+        (WebCore::storeThreadHandleByIdentifier):
+        (WebCore::identifierByThreadHandle):
+        (WebCore::threadHandleForIdentifier):
+        (WebCore::clearThreadHandleForIdentifier):
+        (WebCore::createThread):
+        (WebCore::waitForThreadCompletion):
+        (WebCore::detachThread):
+        (WebCore::currentThread):
+
 2007-12-18  Rodney Dawes  <dobey@wayofthemonkey.com>
 
         Reviewed by Darin Adler.
index cdc47ad98ad83fcfbf920f73e9913848e7cecf32..3cb84c6126b11f6d5b14bb9f3f632275892d59f5 100644 (file)
                                        RelativePath="..\platform\win\MIMETypeRegistryWin.cpp"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath="..\platform\win\MutexWin.cpp"\r
+                                       >\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\platform\win\PasteboardWin.cpp"\r
                                        >\r
                                        RelativePath="..\platform\text\win\TextBreakIteratorInternalICUWin.cpp"\r
                                        >\r
                                </File>\r
+                               <File\r
+                                       RelativePath="..\platform\win\ThreadConditionWin.cpp"\r
+                                       >\r
+                               </File>\r
                                <File\r
                                        RelativePath="..\platform\win\ThreadingWin.cpp"\r
                                        >\r
                                        </File>\r
                                </Filter>\r
                        </Filter>\r
-                       <Filter\r
-                               Name="pthreads"\r
-                               >\r
-                               <File\r
-                                       RelativePath="..\platform\pthreads\ThreadingPthreads.cpp"\r
-                                       >\r
-                               </File>\r
-                       </Filter>\r
                        <Filter\r
                                Name="sql"\r
                                >\r
index 309b8b3a4b4ddde60d76359dcceede39a7af9f3a..0bd0b0b73251c2731f9974049e5fb329e0f41b44 100644 (file)
@@ -93,7 +93,7 @@
 #define WTF_USE_CFNETWORK 1
 #undef WTF_USE_WININET
 #define WTF_PLATFORM_CF 1
-#define WTF_USE_PTHREADS 1
+#define WTF_USE_PTHREADS 0
 #endif
 
 #if PLATFORM(MAC)
index 534e3f6773755a75b10b849d82e21851dd17f8a6..ddb38d1ff62bf8c76bd3e18c4b8c172ecabc44f6 100644 (file)
@@ -69,6 +69,19 @@ typedef GCond* PlatformCondition;
 #elif PLATFORM(QT)
 typedef QMutex* PlatformMutex;
 typedef QWaitCondition* PlatformCondition;
+#elif PLATFORM(WIN_OS)
+struct PlatformMutex {
+    CRITICAL_SECTION m_internalMutex;
+    size_t m_recursionCount;
+};
+struct PlatformCondition {
+    size_t m_timedOut;
+    size_t m_blocked;
+    size_t m_waitingForRemoval;
+    HANDLE m_gate;
+    HANDLE m_queue;
+    HANDLE m_mutex;
+};
 #else
 typedef void* PlatformMutex;
 typedef void* PlatformCondition;
diff --git a/WebCore/platform/win/MutexWin.cpp b/WebCore/platform/win/MutexWin.cpp
new file mode 100644 (file)
index 0000000..41d7fe4
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Brent Fulgham
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "Threading.h"
+
+namespace WebCore {
+
+Mutex::Mutex()
+{
+    m_mutex.m_recursionCount = 0;
+    ::InitializeCriticalSection(&m_mutex.m_internalMutex);
+}
+
+Mutex::~Mutex()
+{
+    ::DeleteCriticalSection(&m_mutex.m_internalMutex);
+}
+
+void Mutex::lock()
+{
+    ::EnterCriticalSection(&m_mutex.m_internalMutex);
+    ++m_mutex.m_recursionCount;
+}
+    
+bool Mutex::tryLock()
+{
+    // This method is modeled after the behavior of pthread_mutex_trylock,
+    // which will return an error if the lock is already owned by the
+    // current thread.  Since the primitive Win32 'TryEnterCriticalSection'
+    // treats this as a successful case, it changes the behavior of several
+    // tests in WebKit that check to see if the current thread already
+    // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
+    DWORD result = ::TryEnterCriticalSection(&m_mutex.m_internalMutex);
+    
+    if (result != 0) {       // We got the lock
+        // If this thread already had the lock, we must unlock and
+        // return false so that we mimic the behavior of POSIX's
+        // pthread_mutex_trylock:
+        if (m_mutex.m_recursionCount > 0) {
+            ::LeaveCriticalSection(&m_mutex.m_internalMutex);
+            return false;
+        }
+
+        ++m_mutex.m_recursionCount;
+        return true;
+    }
+
+    return false;
+}
+
+void Mutex::unlock()
+{
+    --m_mutex.m_recursionCount;
+    ::LeaveCriticalSection(&m_mutex.m_internalMutex);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/ThreadConditionWin.cpp b/WebCore/platform/win/ThreadConditionWin.cpp
new file mode 100644 (file)
index 0000000..f2bdb78
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * =============================================================================
+ * Note:  The implementation of condition variables under the Windows
+ * plaform was based on that of the excellent BOOST C++ library.  It
+ * has been rewritten to fit in with the WebKit architecture and to
+ * use its coding conventions.
+ * =============================================================================
+ *
+ * The Boost license is virtually identical to the Apple variation at the
+ * top of this file, but is included here for completeness:
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+#include "Logging.h"
+#include "Threading.h"
+#include <limits>
+#include <errno.h>
+
+namespace WebCore {
+
+static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
+
+ThreadCondition::ThreadCondition()
+{
+    m_condition.m_timedOut = 0;
+    m_condition.m_blocked = 0;
+    m_condition.m_waitingForRemoval = 0;
+    m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
+    m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
+    m_condition.m_mutex = ::CreateMutex(0, 0, 0);
+
+    if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
+        if (m_condition.m_gate)
+            ::CloseHandle(m_condition.m_gate);
+        if (m_condition.m_queue)
+            ::CloseHandle(m_condition.m_queue);
+        if (m_condition.m_mutex)
+            ::CloseHandle(m_condition.m_mutex);
+    }
+}
+
+ThreadCondition::~ThreadCondition()
+{
+    ::CloseHandle(m_condition.m_gate);
+    ::CloseHandle(m_condition.m_queue);
+    ::CloseHandle(m_condition.m_mutex);
+}
+    
+void ThreadCondition::wait(Mutex& mutex)
+{
+    PlatformMutex& cs = mutex.impl();
+
+    // Enter the wait state.
+    DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+    ASSERT(res == WAIT_OBJECT_0);
+    ++m_condition.m_blocked;
+    res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+    ASSERT(res);
+
+    ::LeaveCriticalSection(&cs.m_internalMutex);
+
+    res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
+    ASSERT(res == WAIT_OBJECT_0);
+
+    res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+    ASSERT(res == WAIT_OBJECT_0);
+    size_t wasWaiting = m_condition.m_waitingForRemoval;
+    size_t wasTimedOut = m_condition.m_timedOut;
+    if (wasWaiting != 0) {
+        if (--m_condition.m_waitingForRemoval == 0) {
+            if (m_condition.m_blocked != 0) {
+                res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);  // open m_gate
+                ASSERT(res);
+                wasWaiting = 0;
+            }
+            else if (m_condition.m_timedOut != 0)
+                m_condition.m_timedOut = 0;
+        }
+    } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
+        // timeout occured, normalize the m_condition.m_timedOut count
+        // this may occur if many calls to wait with a timeout are made and
+        // no call to notify_* is made
+        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+        ASSERT(res == WAIT_OBJECT_0);
+        m_condition.m_blocked -= m_condition.m_timedOut;
+        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+        ASSERT(res);
+        m_condition.m_timedOut = 0;
+    }
+    res = ::ReleaseMutex(m_condition.m_mutex);
+    ASSERT(res);
+
+    if (wasWaiting == 1) {
+        for (/**/ ; wasTimedOut; --wasTimedOut) {
+            // better now than spurious later
+            res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
+            ASSERT(res == WAIT_OBJECT_0);
+        }
+        res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+        ASSERT(res);
+    }
+
+    ::EnterCriticalSection (&cs.m_internalMutex);
+}
+
+void ThreadCondition::signal()
+{
+    unsigned signals = 0;
+
+    DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+    ASSERT(res == WAIT_OBJECT_0);
+
+    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
+        if (m_condition.m_blocked == 0) {
+            res = ::ReleaseMutex(m_condition.m_mutex);
+            ASSERT(res);
+            return;
+        }
+
+        ++m_condition.m_waitingForRemoval;
+        --m_condition.m_blocked;
+
+        signals = 1;
+    } else {
+        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+        ASSERT(res == WAIT_OBJECT_0);
+        if (m_condition.m_blocked > m_condition.m_timedOut) {
+            if (m_condition.m_timedOut != 0) {
+                m_condition.m_blocked -= m_condition.m_timedOut;
+                m_condition.m_timedOut = 0;
+            }
+            signals = m_condition.m_waitingForRemoval = 1;
+            --m_condition.m_blocked;
+        } else {
+            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+            ASSERT(res);
+        }
+    }
+
+    res =::ReleaseMutex(m_condition.m_mutex);
+    ASSERT(res);
+
+    if (signals) {
+        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
+        ASSERT(res);
+    }
+}
+
+void ThreadCondition::broadcast()
+{
+    unsigned signals = 0;
+
+    WORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+    ASSERT(res == WAIT_OBJECT_0);
+
+    if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
+        if (m_condition.m_blocked == 0) {
+            res = ::ReleaseMutex(m_condition.m_mutex);
+            ASSERT(res);
+            return;
+        }
+
+        m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
+        m_condition.m_blocked = 0;
+    } else {
+        res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+        ASSERT(res == WAIT_OBJECT_0);
+        if (m_condition.m_blocked > m_condition.m_timedOut) {
+            if (m_condition.m_timedOut != 0) {
+                m_condition.m_blocked -= m_condition.m_timedOut;
+                m_condition.m_timedOut = 0;
+            }
+            signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
+            m_condition.m_blocked = 0;
+        } else {
+            res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+            ASSERT(res);
+        }
+    }
+
+    res = ::ReleaseMutex(m_condition.m_mutex);
+    ASSERT(res);
+
+    if (signals) {
+        res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
+        ASSERT(res);
+    }
+}
+    
+} // namespace WebCore
index 0b2f3e54a8df36c2b6b326d879f3f2b0752741c3..9890e8ef023ee5aee5a7a97ef3abe4d4c962c0a3 100644 (file)
  */
 
 #include "config.h"
-#include "Threading.h"
-
 #include "Logging.h"
 #include "Page.h"
+#include "Threading.h"
+#include <errno.h>
 #include <windows.h>
+#include <wtf/HashMap.h>
 
 namespace WebCore {
 
@@ -42,6 +43,101 @@ static UINT threadingFiredMessage = 0;
 const LPCWSTR kThreadingWindowClassName = L"ThreadingWindowClass";
 static bool processingCustomThreadingMessage = false;
 
+static Mutex& threadMapMutex()
+{
+    static Mutex mutex;
+    return mutex;
+}
+
+static HashMap<DWORD, HANDLE>& threadMap()
+{
+    static HashMap<DWORD, HANDLE> map;
+    return map;
+}
+
+static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
+{
+    MutexLocker locker(threadMapMutex());
+    threadMap().add(threadID, threadHandle);
+}
+
+static ThreadIdentifier identifierByThreadHandle(HANDLE threadHandle)
+{
+    MutexLocker locker(threadMapMutex());
+
+    HashMap<DWORD, HANDLE>::iterator i = threadMap().begin();
+    for (; i != threadMap().end(); ++i) {
+        if (i->second == threadHandle)
+            return i->first;
+    }
+
+    return 0;
+}
+
+static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
+{
+    MutexLocker locker(threadMapMutex());
+    return threadMap().get(id);
+}
+
+static void clearThreadHandleForIdentifier(ThreadIdentifier id)
+{
+    MutexLocker locker(threadMapMutex());
+    ASSERT(threadMap().contains(id));
+    threadMap().remove(id);
+}
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
+{
+    DWORD threadIdentifier = 0;
+    ThreadIdentifier threadID = 0;
+    HANDLE hEvent = ::CreateEvent(0, FALSE, FALSE, 0);
+    HANDLE threadHandle = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)entryPoint, data, 0, &threadIdentifier);
+    if (!threadHandle) {
+        LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
+        return 0;
+    }
+
+    threadID = static_cast<ThreadIdentifier>(threadIdentifier);
+    storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
+
+    LOG(Threading, "Created thread with thread id %u", threadID);
+    return threadID;
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+    ASSERT(threadID);
+    
+    HANDLE threadHandle = threadHandleForIdentifier(threadID);
+    if (!threadHandle)
+        LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
+    DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
+    if (joinResult == WAIT_FAILED)
+        LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
+
+    ::CloseHandle(threadHandle);
+    clearThreadHandleForIdentifier(threadID);
+
+    return joinResult;
+}
+
+void detachThread(ThreadIdentifier threadID)
+{
+    ASSERT(threadID);
+    
+    HANDLE threadHandle = threadHandleForIdentifier(threadID);
+    if (threadHandle)
+        ::CloseHandle(threadHandle);
+    clearThreadHandleForIdentifier(threadID);
+}
+
+ThreadIdentifier currentThread()
+{
+    return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
+}
+
 static Mutex& functionQueueMutex()
 {
     static Mutex staticFunctionQueueMutex;