summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/Platform/win/WorkQueueWin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/Platform/win/WorkQueueWin.cpp')
-rw-r--r--Source/WebKit2/Platform/win/WorkQueueWin.cpp61
1 files changed, 59 insertions, 2 deletions
diff --git a/Source/WebKit2/Platform/win/WorkQueueWin.cpp b/Source/WebKit2/Platform/win/WorkQueueWin.cpp
index f527432..f751b5d 100644
--- a/Source/WebKit2/Platform/win/WorkQueueWin.cpp
+++ b/Source/WebKit2/Platform/win/WorkQueueWin.cpp
@@ -23,6 +23,7 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
#include "WorkQueue.h"
#include <wtf/Threading.h>
@@ -164,6 +165,8 @@ void WorkQueue::performWorkOnRegisteredWorkThread()
void WorkQueue::platformInitialize(const char* name)
{
m_isWorkThreadRegistered = 0;
+ m_timerQueue = ::CreateTimerQueue();
+ ASSERT_WITH_MESSAGE(m_timerQueue, "::CreateTimerQueue failed with error %lu", ::GetLastError());
}
bool WorkQueue::tryRegisterAsWorkThread()
@@ -185,6 +188,10 @@ void WorkQueue::platformInvalidate()
MutexLocker lock(m_handlesLock);
ASSERT(m_handles.isEmpty());
#endif
+
+ // FIXME: We need to ensure that any timer-queue timers that fire after this point don't try to
+ // access this WorkQueue <http://webkit.org/b/44690>.
+ ::DeleteTimerQueueEx(m_timerQueue, 0);
}
void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item)
@@ -203,9 +210,59 @@ void WorkQueue::scheduleWork(PassOwnPtr<WorkItem> item)
::QueueUserWorkItem(workThreadCallback, this, WT_EXECUTEDEFAULT);
}
-void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double)
+struct TimerContext : public ThreadSafeShared<TimerContext> {
+ static PassRefPtr<TimerContext> create() { return adoptRef(new TimerContext); }
+
+ WorkQueue* queue;
+ OwnPtr<WorkItem> item;
+ Mutex timerMutex;
+ HANDLE timer;
+
+private:
+ TimerContext() : queue(0), timer(0) { }
+};
+
+void WorkQueue::timerCallback(void* context, BOOLEAN timerOrWaitFired)
+{
+ ASSERT_ARG(context, context);
+ ASSERT_UNUSED(timerOrWaitFired, timerOrWaitFired);
+
+ // Balanced by leakRef in scheduleWorkAfterDelay.
+ RefPtr<TimerContext> timerContext = adoptRef(static_cast<TimerContext*>(context));
+
+ timerContext->queue->scheduleWork(timerContext->item.release());
+
+ MutexLocker lock(timerContext->timerMutex);
+ ASSERT(timerContext->timer);
+ ASSERT(timerContext->queue->m_timerQueue);
+ if (!::DeleteTimerQueueTimer(timerContext->queue->m_timerQueue, timerContext->timer, 0))
+ ASSERT_WITH_MESSAGE(false, "::DeleteTimerQueueTimer failed with error %lu", ::GetLastError());
+}
+
+void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem> item, double delay)
{
- notImplemented();
+ ASSERT(m_timerQueue);
+
+ RefPtr<TimerContext> context = TimerContext::create();
+ context->queue = this;
+ context->item = item;
+
+ {
+ // The timer callback could fire before ::CreateTimerQueueTimer even returns, so we protect
+ // context->timer with a mutex to ensure the timer callback doesn't access it before the
+ // timer handle has been stored in it.
+ MutexLocker lock(context->timerMutex);
+
+ // Since our timer callback is quick, we can execute in the timer thread itself and avoid
+ // an extra thread switch over to a worker thread.
+ if (!::CreateTimerQueueTimer(&context->timer, m_timerQueue, timerCallback, context.get(), delay * 1000, 0, WT_EXECUTEINTIMERTHREAD)) {
+ ASSERT_WITH_MESSAGE(false, "::CreateTimerQueueTimer failed with error %lu", ::GetLastError());
+ return;
+ }
+ }
+
+ // The timer callback will handle destroying context.
+ context.release().leakRef();
}
void WorkQueue::unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem> item)