summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/Platform/win
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/Platform/win')
-rw-r--r--Source/WebKit2/Platform/win/ModuleWin.cpp55
-rw-r--r--Source/WebKit2/Platform/win/RunLoopWin.cpp170
-rw-r--r--Source/WebKit2/Platform/win/SharedMemoryWin.cpp188
-rw-r--r--Source/WebKit2/Platform/win/WorkQueueWin.cpp234
4 files changed, 647 insertions, 0 deletions
diff --git a/Source/WebKit2/Platform/win/ModuleWin.cpp b/Source/WebKit2/Platform/win/ModuleWin.cpp
new file mode 100644
index 0000000..2c2250d
--- /dev/null
+++ b/Source/WebKit2/Platform/win/ModuleWin.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "Module.h"
+
+#include <shlwapi.h>
+
+namespace WebKit {
+
+bool Module::load()
+{
+ ASSERT(!::PathIsRelativeW(m_path.charactersWithNullTermination()));
+ m_module = ::LoadLibraryExW(m_path.charactersWithNullTermination(), 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ return m_module;
+}
+
+void Module::unload()
+{
+ if (!m_module)
+ return;
+ ::FreeLibrary(m_module);
+ m_module = 0;
+}
+
+void* Module::platformFunctionPointer(const char* functionName) const
+{
+ if (!m_module)
+ return 0;
+
+ return ::GetProcAddress(m_module, functionName);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/Platform/win/RunLoopWin.cpp b/Source/WebKit2/Platform/win/RunLoopWin.cpp
new file mode 100644
index 0000000..4dfb4b5
--- /dev/null
+++ b/Source/WebKit2/Platform/win/RunLoopWin.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "RunLoop.h"
+
+#include "WorkItem.h"
+
+static const UINT PerformWorkMessage = WM_USER + 1;
+static const LPWSTR kRunLoopMessageWindowClassName = L"RunLoopMessageWindow";
+
+LRESULT CALLBACK RunLoop::RunLoopWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LONG_PTR longPtr = ::GetWindowLongPtr(hWnd, 0);
+
+ if (RunLoop* runLoop = reinterpret_cast<RunLoop*>(longPtr))
+ return runLoop->wndProc(hWnd, message, wParam, lParam);
+
+ if (message == WM_CREATE) {
+ LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
+
+ // Associate the RunLoop with the window.
+ ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams);
+ return 0;
+ }
+
+ return ::DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+LRESULT RunLoop::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case PerformWorkMessage:
+ performWork();
+ return 0;
+ case WM_TIMER:
+ RunLoop::TimerBase::timerFired(this, wParam);
+ return 0;
+ }
+
+ return ::DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void RunLoop::run()
+{
+ MSG message;
+ while (BOOL result = ::GetMessage(&message, 0, 0, 0)) {
+ if (result == -1)
+ break;
+ ::TranslateMessage(&message);
+ ::DispatchMessage(&message);
+ }
+}
+
+void RunLoop::stop()
+{
+ ::PostQuitMessage(0);
+}
+
+bool RunLoop::registerRunLoopMessageWindowClass()
+{
+ // FIXME: This really only needs to be called once.
+
+ WNDCLASSEX windowClass = { 0 };
+ windowClass.cbSize = sizeof(windowClass);
+ windowClass.lpfnWndProc = RunLoop::RunLoopWndProc;
+ windowClass.cbWndExtra = sizeof(RunLoop*);
+ windowClass.lpszClassName = kRunLoopMessageWindowClassName;
+
+ return !!::RegisterClassEx(&windowClass);
+}
+
+RunLoop::RunLoop()
+{
+ registerRunLoopMessageWindowClass();
+
+ m_runLoopMessageWindow = ::CreateWindow(kRunLoopMessageWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ HWND_MESSAGE, 0, 0, this);
+ ASSERT(::IsWindow(m_runLoopMessageWindow));
+}
+
+RunLoop::~RunLoop()
+{
+ // FIXME: Tear down the work item queue here.
+}
+
+void RunLoop::wakeUp()
+{
+ // FIXME: No need to wake up the run loop if we've already called scheduleWork
+ // before the run loop has had the time to respond.
+ ::PostMessage(m_runLoopMessageWindow, PerformWorkMessage, reinterpret_cast<WPARAM>(this), 0);
+}
+
+// RunLoop::Timer
+
+void RunLoop::TimerBase::timerFired(RunLoop* runLoop, uint64_t ID)
+{
+ TimerMap::iterator it = runLoop->m_activeTimers.find(ID);
+ ASSERT(it != runLoop->m_activeTimers.end());
+ TimerBase* timer = it->second;
+
+ if (!timer->m_isRepeating) {
+ runLoop->m_activeTimers.remove(it);
+ ::KillTimer(runLoop->m_runLoopMessageWindow, ID);
+ }
+
+ timer->fired();
+}
+
+static uint64_t generateTimerID()
+{
+ static uint64_t uniqueTimerID = 1;
+ return uniqueTimerID++;
+}
+
+RunLoop::TimerBase::TimerBase(RunLoop* runLoop)
+ : m_runLoop(runLoop)
+ , m_ID(generateTimerID())
+ , m_isRepeating(false)
+{
+}
+
+RunLoop::TimerBase::~TimerBase()
+{
+ stop();
+}
+
+void RunLoop::TimerBase::start(double nextFireInterval, bool repeat)
+{
+ m_isRepeating = repeat;
+ m_runLoop->m_activeTimers.set(m_ID, this);
+ ::SetTimer(m_runLoop->m_runLoopMessageWindow, m_ID, nextFireInterval, 0);
+}
+
+void RunLoop::TimerBase::stop()
+{
+ TimerMap::iterator it = m_runLoop->m_activeTimers.find(m_ID);
+ if (it == m_runLoop->m_activeTimers.end())
+ return;
+
+ m_runLoop->m_activeTimers.remove(it);
+ ::KillTimer(m_runLoop->m_runLoopMessageWindow, m_ID);
+}
+
+bool RunLoop::TimerBase::isActive() const
+{
+ return m_runLoop->m_activeTimers.contains(m_ID);
+}
diff --git a/Source/WebKit2/Platform/win/SharedMemoryWin.cpp b/Source/WebKit2/Platform/win/SharedMemoryWin.cpp
new file mode 100644
index 0000000..260783a
--- /dev/null
+++ b/Source/WebKit2/Platform/win/SharedMemoryWin.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "SharedMemory.h"
+
+#include "ArgumentDecoder.h"
+#include "ArgumentEncoder.h"
+#include <wtf/RefPtr.h>
+
+namespace WebKit {
+
+SharedMemory::Handle::Handle()
+ : m_handle(0)
+ , m_size(0)
+{
+}
+
+SharedMemory::Handle::~Handle()
+{
+ if (!m_handle)
+ return;
+
+ ::CloseHandle(m_handle);
+}
+
+void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const
+{
+ encoder->encodeUInt64(m_size);
+
+ // Hand off ownership of our HANDLE to the receiving process. It will close it for us.
+ // FIXME: If the receiving process crashes before it receives the memory, the memory will be
+ // leaked. See <http://webkit.org/b/47502>.
+ encoder->encodeUInt64(reinterpret_cast<uint64_t>(m_handle));
+ m_handle = 0;
+
+ // Send along our PID so that the receiving process can duplicate the HANDLE for its own use.
+ encoder->encodeUInt32(::GetCurrentProcessId());
+}
+
+bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle)
+{
+ ASSERT_ARG(handle, !handle.m_handle);
+ ASSERT_ARG(handle, !handle.m_size);
+
+ uint64_t size;
+ if (!decoder->decodeUInt64(size))
+ return false;
+
+ uint64_t sourceHandle;
+ if (!decoder->decodeUInt64(sourceHandle))
+ return false;
+
+ uint32_t sourcePID;
+ if (!decoder->decodeUInt32(sourcePID))
+ return false;
+
+ HANDLE sourceProcess = ::OpenProcess(PROCESS_DUP_HANDLE, FALSE, sourcePID);
+ if (!sourceProcess)
+ return false;
+
+ // Copy the handle into our process and close the handle that the sending process created for us.
+ HANDLE duplicatedHandle;
+ BOOL success = ::DuplicateHandle(sourceProcess, reinterpret_cast<HANDLE>(sourceHandle), ::GetCurrentProcess(), &duplicatedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+
+ ::CloseHandle(sourceProcess);
+
+ if (!success)
+ return false;
+
+ handle.m_handle = duplicatedHandle;
+ handle.m_size = size;
+ return true;
+}
+
+PassRefPtr<SharedMemory> SharedMemory::create(size_t size)
+{
+ HANDLE handle = ::CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, 0);
+ if (!handle)
+ return 0;
+
+ void* baseAddress = ::MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, size);
+ if (!baseAddress) {
+ ::CloseHandle(handle);
+ return 0;
+ }
+
+ RefPtr<SharedMemory> memory = adoptRef(new SharedMemory);
+ memory->m_size = size;
+ memory->m_data = baseAddress;
+ memory->m_handle = handle;
+
+ return memory.release();
+}
+
+static DWORD accessRights(SharedMemory::Protection protection)
+{
+ switch (protection) {
+ case SharedMemory::ReadOnly:
+ return FILE_MAP_READ;
+ case SharedMemory::ReadWrite:
+ // FILE_MAP_WRITE implies read access, too.
+ return FILE_MAP_WRITE;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection)
+{
+ DWORD desiredAccess = accessRights(protection);
+
+ void* baseAddress = ::MapViewOfFile(handle.m_handle, desiredAccess, 0, 0, handle.m_size);
+ if (!baseAddress)
+ return 0;
+
+ RefPtr<SharedMemory> memory = adoptRef(new SharedMemory);
+ memory->m_size = handle.m_size;
+ memory->m_data = baseAddress;
+
+ // Adopt the HANDLE.
+ memory->m_handle = handle.m_handle;
+ handle.m_handle = 0;
+
+ return memory.release();
+}
+
+SharedMemory::~SharedMemory()
+{
+ ASSERT(m_data);
+ ASSERT(m_handle);
+
+ ::UnmapViewOfFile(m_data);
+ ::CloseHandle(m_handle);
+}
+
+bool SharedMemory::createHandle(Handle& handle, Protection protection)
+{
+ ASSERT_ARG(handle, !handle.m_handle);
+ ASSERT_ARG(handle, !handle.m_size);
+
+ HANDLE processHandle = ::GetCurrentProcess();
+
+ HANDLE duplicatedHandle;
+ if (!::DuplicateHandle(processHandle, m_handle, processHandle, &duplicatedHandle, accessRights(protection), FALSE, 0))
+ return false;
+
+ handle.m_handle = duplicatedHandle;
+ handle.m_size = m_size;
+ return true;
+}
+
+unsigned SharedMemory::systemPageSize()
+{
+ static unsigned pageSize = 0;
+
+ if (!pageSize) {
+ SYSTEM_INFO systemInfo;
+ ::GetSystemInfo(&systemInfo);
+ pageSize = systemInfo.dwPageSize;
+ }
+
+ return pageSize;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit2/Platform/win/WorkQueueWin.cpp b/Source/WebKit2/Platform/win/WorkQueueWin.cpp
new file mode 100644
index 0000000..f527432
--- /dev/null
+++ b/Source/WebKit2/Platform/win/WorkQueueWin.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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 "WorkQueue.h"
+
+#include <wtf/Threading.h>
+#include "NotImplemented.h"
+
+inline WorkQueue::WorkItemWin::WorkItemWin(PassOwnPtr<WorkItem> item, WorkQueue* queue)
+ : m_item(item)
+ , m_queue(queue)
+{
+}
+
+PassRefPtr<WorkQueue::WorkItemWin> WorkQueue::WorkItemWin::create(PassOwnPtr<WorkItem> item, WorkQueue* queue)
+{
+ return adoptRef(new WorkItemWin(item, queue));
+}
+
+WorkQueue::WorkItemWin::~WorkItemWin()
+{
+}
+
+inline WorkQueue::HandleWorkItem::HandleWorkItem(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue)
+ : WorkItemWin(item, queue)
+ , m_handle(handle)
+ , m_waitHandle(0)
+{
+ ASSERT_ARG(handle, handle);
+}
+
+PassRefPtr<WorkQueue::HandleWorkItem> WorkQueue::HandleWorkItem::createByAdoptingHandle(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue)
+{
+ return adoptRef(new HandleWorkItem(handle, item, queue));
+}
+
+WorkQueue::HandleWorkItem::~HandleWorkItem()
+{
+ ::CloseHandle(m_handle);
+}
+
+void WorkQueue::handleCallback(void* context, BOOLEAN timerOrWaitFired)
+{
+ ASSERT_ARG(context, context);
+ ASSERT_ARG(timerOrWaitFired, !timerOrWaitFired);
+
+ WorkItemWin* item = static_cast<WorkItemWin*>(context);
+ WorkQueue* queue = item->queue();
+
+ {
+ MutexLocker lock(queue->m_workItemQueueLock);
+ queue->m_workItemQueue.append(item);
+
+ // If no other thread is performing work, we can do it on this thread.
+ if (!queue->tryRegisterAsWorkThread()) {
+ // Some other thread is performing work. Since we hold the queue lock, we can be sure
+ // that the work thread is not exiting due to an empty queue and will process the work
+ // item we just added to it. If we weren't holding the lock we'd have to signal
+ // m_performWorkEvent to make sure the work item got picked up.
+ return;
+ }
+ }
+
+ queue->performWorkOnRegisteredWorkThread();
+}
+
+void WorkQueue::registerHandle(HANDLE handle, PassOwnPtr<WorkItem> item)
+{
+ RefPtr<HandleWorkItem> handleItem = HandleWorkItem::createByAdoptingHandle(handle, item, this);
+
+ {
+ MutexLocker lock(m_handlesLock);
+ ASSERT_ARG(handle, !m_handles.contains(handle));
+ m_handles.set(handle, handleItem);
+ }
+
+ HANDLE waitHandle;
+ if (!::RegisterWaitForSingleObject(&waitHandle, handle, handleCallback, handleItem.get(), INFINITE, WT_EXECUTEDEFAULT)) {
+ DWORD error = ::GetLastError();
+ ASSERT_NOT_REACHED();
+ }
+ handleItem->setWaitHandle(waitHandle);
+}
+
+void WorkQueue::unregisterAndCloseHandle(HANDLE handle)
+{
+ RefPtr<HandleWorkItem> item;
+ {
+ MutexLocker locker(m_handlesLock);
+ ASSERT_ARG(handle, m_handles.contains(handle));
+ item = m_handles.take(handle);
+ }
+
+ unregisterWaitAndDestroyItemSoon(item.release());
+}
+
+DWORD WorkQueue::workThreadCallback(void* context)
+{
+ ASSERT_ARG(context, context);
+
+ WorkQueue* queue = static_cast<WorkQueue*>(context);
+
+ if (!queue->tryRegisterAsWorkThread())
+ return 0;
+
+ queue->performWorkOnRegisteredWorkThread();
+ return 0;
+}
+
+void WorkQueue::performWorkOnRegisteredWorkThread()
+{
+ ASSERT(m_isWorkThreadRegistered);
+
+ bool isValid = true;
+
+ m_workItemQueueLock.lock();
+
+ while (isValid && !m_workItemQueue.isEmpty()) {
+ Vector<RefPtr<WorkItemWin> > workItemQueue;
+ m_workItemQueue.swap(workItemQueue);
+
+ // Allow more work to be scheduled while we're not using the queue directly.
+ m_workItemQueueLock.unlock();
+ for (size_t i = 0; i < workItemQueue.size(); ++i) {
+ MutexLocker locker(m_isValidMutex);
+ isValid = m_isValid;
+ if (!isValid)
+ break;
+ workItemQueue[i]->item()->execute();
+ }
+ m_workItemQueueLock.lock();
+ }
+
+ // One invariant we maintain is that any work scheduled while a work thread is registered will
+ // be handled by that work thread. Unregister as the work thread while the queue lock is still
+ // held so that no work can be scheduled while we're still registered.
+ unregisterAsWorkThread();
+
+ m_workItemQueueLock.unlock();
+}
+
+void WorkQueue::platformInitialize(const char* name)
+{
+ m_isWorkThreadRegistered = 0;
+}
+
+bool WorkQueue::tryRegisterAsWorkThread()
+{
+ LONG result = ::InterlockedCompareExchange(&m_isWorkThreadRegistered, 1, 0);
+ ASSERT(!result || result == 1);
+ return !result;
+}
+
+void WorkQueue::unregisterAsWorkThread()
+{
+ LONG result = ::InterlockedCompareExchange(&m_isWorkThreadRegistered, 0, 1);
+ ASSERT_UNUSED(result, result == 1);
+}
+
+void WorkQueue::platformInvalidate()
+{
+#if !ASSERT_DISABLED
+ MutexLocker lock(m_handlesLock);
+ ASSERT(m_handles.isEmpty());
+#endif
+}
+
+void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item)
+{
+ MutexLocker locker(m_workItemQueueLock);
+
+ m_workItemQueue.append(WorkItemWin::create(item, this));
+
+ // Spawn a work thread to perform the work we just added. As an optimization, we avoid
+ // spawning the thread if a work thread is already registered. This prevents multiple work
+ // threads from being spawned in most cases. (Note that when a work thread has been spawned but
+ // hasn't registered itself yet, m_isWorkThreadRegistered will be false and we'll end up
+ // spawning a second work thread here. But work thread registration process will ensure that
+ // only one thread actually ends up performing work.)
+ if (!m_isWorkThreadRegistered)
+ ::QueueUserWorkItem(workThreadCallback, this, WT_EXECUTEDEFAULT);
+}
+
+void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double)
+{
+ notImplemented();
+}
+
+void WorkQueue::unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem> item)
+{
+ // We're going to make a blocking call to ::UnregisterWaitEx before closing the handle. (The
+ // blocking version of ::UnregisterWaitEx is much simpler than the non-blocking version.) If we
+ // do this on the current thread, we'll deadlock if we're currently in a callback function for
+ // the wait we're unregistering. So instead we do it asynchronously on some other worker thread.
+
+ ::QueueUserWorkItem(unregisterWaitAndDestroyItemCallback, item.leakRef(), WT_EXECUTEDEFAULT);
+}
+
+DWORD WINAPI WorkQueue::unregisterWaitAndDestroyItemCallback(void* context)
+{
+ ASSERT_ARG(context, context);
+ RefPtr<HandleWorkItem> item = adoptRef(static_cast<HandleWorkItem*>(context));
+
+ // Now that we know we're not in a callback function for the wait we're unregistering, we can
+ // make a blocking call to ::UnregisterWaitEx.
+ if (!::UnregisterWaitEx(item->waitHandle(), INVALID_HANDLE_VALUE)) {
+ DWORD error = ::GetLastError();
+ ASSERT_NOT_REACHED();
+ }
+
+ return 0;
+}