Index: Source/platform/scheduler/Scheduler.cpp |
diff --git a/Source/platform/scheduler/Scheduler.cpp b/Source/platform/scheduler/Scheduler.cpp |
index 61ae7aef1d486bd618417a2d2d62c14c08db06bc..d7a8d1b437ca4cd876b4f4561a5fe5477c6c501a 100644 |
--- a/Source/platform/scheduler/Scheduler.cpp |
+++ b/Source/platform/scheduler/Scheduler.cpp |
@@ -5,38 +5,18 @@ |
#include "config.h" |
#include "platform/scheduler/Scheduler.h" |
+#include "platform/PlatformThreadData.h" |
#include "platform/Task.h" |
+#include "platform/ThreadTimers.h" |
#include "platform/TraceEvent.h" |
-#include "platform/TraceLocation.h" |
#include "public/platform/Platform.h" |
#include "public/platform/WebThread.h" |
+#include "wtf/Atomics.h" |
namespace blink { |
namespace { |
-class MainThreadTaskAdapter : public blink::WebThread::Task { |
-public: |
- explicit MainThreadTaskAdapter(const TraceLocation& location, const Scheduler::Task& task) |
- : m_location(location) |
- , m_task(task) |
- { |
- } |
- |
- // WebThread::Task implementation. |
- virtual void run() OVERRIDE |
- { |
- TRACE_EVENT2("blink", "MainThreadTaskAdapter::run", |
- "src_file", m_location.fileName(), |
- "src_func", m_location.functionName()); |
- m_task(); |
- } |
- |
-private: |
- const TraceLocation m_location; |
- Scheduler::Task m_task; |
-}; |
- |
class MainThreadIdleTaskAdapter : public blink::WebThread::Task { |
public: |
MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allottedTimeMs) |
@@ -57,6 +37,16 @@ private: |
double m_allottedTimeMs; |
}; |
+class MainThreadPendingTaskRunner : public blink::WebThread::Task { |
+public: |
+ // WebThread::Task implementation. |
+ virtual void run() OVERRIDE |
+ { |
+ Scheduler::shared()->runPendingTasks(); |
+ Scheduler::shared()->allowMainThreadTaskPosting(); |
+ } |
+}; |
+ |
} |
Scheduler* Scheduler::s_sharedScheduler = nullptr; |
@@ -79,17 +69,15 @@ Scheduler* Scheduler::shared() |
Scheduler::Scheduler() |
: m_mainThread(blink::Platform::current()->currentThread()) |
+ , m_mainThreadTaskPosted(0) |
+ , m_blinkShouldNotYield(1) |
, m_sharedTimerFunction(nullptr) |
{ |
} |
Scheduler::~Scheduler() |
{ |
-} |
- |
-void Scheduler::scheduleTask(const TraceLocation& location, const Task& task) |
-{ |
- m_mainThread->postTask(new MainThreadTaskAdapter(location, task)); |
+ runPendingTasks(); |
} |
void Scheduler::scheduleIdleTask(const IdleTask& idleTask) |
@@ -100,17 +88,24 @@ void Scheduler::scheduleIdleTask(const IdleTask& idleTask) |
void Scheduler::postTask(const TraceLocation& location, const Task& task) |
{ |
- scheduleTask(location, task); |
+ m_pendingBlinkTasks.append(TracedTask(task, location)); |
+ maybePostTaskLoopOnMainThread(); |
} |
void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
{ |
- scheduleTask(location, task); |
+ m_pendingInputTasks.pushMaySpinlock(new TracedTask(task, location)); |
+ maybePostTaskLoopOnMainThread(); |
+ |
+ setBlinkShouldYield(); |
} |
void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task) |
{ |
- scheduleTask(location, task); |
+ m_pendingCompositorTasks.pushMaySpinlock(new TracedTask(task, location)); |
+ maybePostTaskLoopOnMainThread(); |
+ |
+ setBlinkShouldYield(); |
} |
void Scheduler::postIdleTask(const IdleTask& idleTask) |
@@ -121,9 +116,67 @@ void Scheduler::postIdleTask(const IdleTask& idleTask) |
void Scheduler::tickSharedTimer() |
{ |
TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); |
+ |
+ // Execute any pending tasks. |
+ if (shouldYieldForHighPriorityWork()) |
+ runPendingTasks(); |
+ |
m_sharedTimerFunction(); |
} |
+void Scheduler::runPendingTasks() |
+{ |
+ TRACE_EVENT0("blink", "Scheduler::runPendingTasks"); |
+ |
+ // Execute tasks from the queues in order of priority. |
+ for (;;) { |
+ TracedTask* task = m_pendingInputTasks.pop(); |
Sami
2014/08/06 10:19:52
How about making this slightly safer by wrapping t
alexclarke
2014/08/07 12:08:06
Done.
|
+ if (task) { |
+ task->run(); |
+ delete task; |
+ continue; |
+ } |
+ |
+ task = m_pendingCompositorTasks.pop(); |
+ if (task) { |
+ task->run(); |
+ delete task; |
+ continue; |
+ } |
+ |
+ if (m_pendingBlinkTasks.isEmpty()) |
+ break; |
+ |
+ m_pendingBlinkTasks.takeFirst().run(); |
Sami
2014/08/06 10:19:52
It seems like it's possible for low priority tasks
alexclarke
2014/08/07 12:08:06
It's also possible for compositor tasks to do some
|
+ } |
+ |
+ clearBlinkShouldYield(); |
+} |
+ |
+void Scheduler::maybePostTaskLoopOnMainThread() |
+{ |
+ if (atomicTestAndSetToOne(&m_mainThreadTaskPosted)) |
+ return; |
+ |
+ m_mainThread->postTask(new MainThreadPendingTaskRunner()); |
+} |
+ |
+void Scheduler::allowMainThreadTaskPosting() |
+{ |
+ // Allow posting of the main thread task again. |
+ atomicSetOneToZero(&m_mainThreadTaskPosted); |
+} |
+ |
+void Scheduler::setBlinkShouldYield() |
+{ |
+ atomicSetOneToZero(&m_blinkShouldNotYield); |
+} |
+ |
+void Scheduler::clearBlinkShouldYield() |
+{ |
+ atomicTestAndSetToOne(&m_blinkShouldNotYield); |
+} |
+ |
void Scheduler::sharedTimerAdapter() |
{ |
shared()->tickSharedTimer(); |
@@ -147,7 +200,15 @@ void Scheduler::stopSharedTimer() |
bool Scheduler::shouldYieldForHighPriorityWork() |
{ |
- return false; |
+ return !atomicTestAndSetToOne(&m_blinkShouldNotYield); |
+} |
+ |
+void Scheduler::TracedTask::run() |
+{ |
+ TRACE_EVENT2("blink", "TracedTask::run", |
+ "src_file", m_location.fileName(), |
+ "src_func", m_location.functionName()); |
+ m_task(); |
} |
} // namespace blink |