Index: Source/core/workers/WorkerThread.cpp |
diff --git a/Source/core/workers/WorkerThread.cpp b/Source/core/workers/WorkerThread.cpp |
index 6b444d379c3e6da148216e69ff8901912ea97fad..a46ed71804ba9eb3ffeb52c068f801e86f565440 100644 |
--- a/Source/core/workers/WorkerThread.cpp |
+++ b/Source/core/workers/WorkerThread.cpp |
@@ -85,12 +85,40 @@ unsigned WorkerThread::workerThreadCount() |
return workerThreads().size(); |
} |
+class WorkerThreadCancelableTask FINAL : public ExecutionContextTask { |
+ WTF_MAKE_NONCOPYABLE(WorkerThreadCancelableTask); WTF_MAKE_FAST_ALLOCATED; |
+public: |
+ static PassOwnPtr<WorkerThreadCancelableTask> create(const Closure& closure) |
+ { |
+ return adoptPtr(new WorkerThreadCancelableTask(closure)); |
+ } |
+ |
+ virtual void performTask(ExecutionContext*) OVERRIDE |
+ { |
+ if (!m_taskCanceled) |
+ m_closure(); |
+ } |
+ |
+ void cancelTask() { m_taskCanceled = true; } |
+ |
+private: |
+ explicit WorkerThreadCancelableTask(const Closure& closure) |
+ : m_closure(closure) |
+ , m_taskCanceled(false) |
+ { } |
+ |
+ Closure m_closure; |
+ bool m_taskCanceled; |
+}; |
+ |
class WorkerSharedTimer : public SharedTimer { |
public: |
explicit WorkerSharedTimer(WorkerThread* workerThread) |
: m_workerThread(workerThread) |
, m_nextFireTime(0.0) |
, m_running(false) |
+ , m_lastQueuedTask(0) |
+ , m_lastQueuedTaskTimer(0) |
{ } |
typedef void (*SharedTimerFunction)(); |
@@ -116,12 +144,28 @@ public: |
m_running = true; |
m_nextFireTime = currentTime() + interval; |
- m_workerThread->postDelayedTask(createSameThreadTask(&WorkerSharedTimer::OnTimeout, this), delay); |
+ if (m_lastQueuedTask) { |
+ // If something was queued up before this, check if its later than the current timer |
+ if (interval < m_lastQueuedTaskTimer->nextFireInterval()) { |
+ m_lastQueuedTask->cancelTask(); |
+ m_lastQueuedTask = 0; |
+ m_lastQueuedTaskTimer = 0; |
+ } |
+ } |
+ if (!m_lastQueuedTask) { |
+ // Now queue the task as a cancellable one. |
+ m_lastQueuedTask = WorkerThreadCancelableTask::create(bind(&WorkerSharedTimer::OnTimeout, this)).leakPtr(); |
+ m_workerThread->postDelayedTask(adoptPtr(m_lastQueuedTask), delay); |
+ // The current timer should ideally be at the top of the heap as its assumed to be the smallest interval in the heap |
+ m_lastQueuedTaskTimer = PlatformThreadData::current().threadTimers().timerHeap().first(); |
+ } |
} |
virtual void stop() |
{ |
m_running = false; |
+ m_lastQueuedTask = 0; |
+ m_lastQueuedTaskTimer = 0; |
} |
double nextFireTime() { return m_nextFireTime; } |
@@ -130,6 +174,10 @@ private: |
void OnTimeout() |
{ |
ASSERT(m_workerThread->workerGlobalScope()); |
+ |
+ m_lastQueuedTask = 0; |
+ m_lastQueuedTaskTimer = 0; |
+ |
if (m_sharedTimerFunction && m_running && !m_workerThread->workerGlobalScope()->isClosing()) |
m_sharedTimerFunction(); |
} |
@@ -138,6 +186,8 @@ private: |
SharedTimerFunction m_sharedTimerFunction; |
double m_nextFireTime; |
bool m_running; |
+ WorkerThreadCancelableTask* m_lastQueuedTask; |
+ TimerBase* m_lastQueuedTaskTimer; |
}; |
class WorkerThreadTask : public blink::WebThread::Task { |