Chromium Code Reviews| Index: Source/platform/scheduler/Scheduler.cpp |
| diff --git a/Source/platform/scheduler/Scheduler.cpp b/Source/platform/scheduler/Scheduler.cpp |
| index 61ae7aef1d486bd618417a2d2d62c14c08db06bc..5bfe8b34c7a9acd128fb8abb5a59f4081083d0e1 100644 |
| --- a/Source/platform/scheduler/Scheduler.cpp |
| +++ b/Source/platform/scheduler/Scheduler.cpp |
| @@ -5,59 +5,103 @@ |
| #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/ThreadingPrimitives.h" |
| namespace blink { |
| namespace { |
| -class MainThreadTaskAdapter : public blink::WebThread::Task { |
| +class MainThreadIdleTaskAdapter : public WebThread::Task { |
|
eseidel
2014/08/11 17:02:36
Might add a comment to note that this can be creat
alexclarke
2014/08/12 11:37:02
Done.
|
| public: |
| - explicit MainThreadTaskAdapter(const TraceLocation& location, const Scheduler::Task& task) |
| - : m_location(location) |
| - , m_task(task) |
| + MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allottedTimeMs, const TraceLocation& location) |
| + : m_idleTask(idleTask) |
| + , m_allottedTimeMs(allottedTimeMs) |
|
eseidel
2014/08/11 17:02:36
Might have called this timeout or maxDuration, but
alexclarke
2014/08/12 11:37:02
Acknowledged.
|
| + , m_location(location) |
| { |
|
eseidel
2014/08/11 17:02:36
If this can't be created from any thread, we shoul
alexclarke
2014/08/12 11:37:02
It can be called from any thread.
|
| } |
| // WebThread::Task implementation. |
| virtual void run() OVERRIDE |
| { |
| - TRACE_EVENT2("blink", "MainThreadTaskAdapter::run", |
| + TRACE_EVENT2("blink", "MainThreadIdleTaskAdapter::run", |
| "src_file", m_location.fileName(), |
| "src_func", m_location.functionName()); |
| - m_task(); |
| + m_idleTask(m_allottedTimeMs); |
| } |
| private: |
| - const TraceLocation m_location; |
| - Scheduler::Task m_task; |
| + Scheduler::IdleTask m_idleTask; |
| + double m_allottedTimeMs; |
| + TraceLocation m_location; |
| }; |
| -class MainThreadIdleTaskAdapter : public blink::WebThread::Task { |
| +} // namespace |
| + |
| +class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Task { |
| public: |
| - MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allottedTimeMs) |
| - : m_idleTask(idleTask) |
| - , m_allottedTimeMs(allottedTimeMs) |
| + MainThreadPendingHighPriorityTaskRunner() |
| + { |
| + ASSERT(Scheduler::shared()); |
| + Scheduler::shared()->incrementMainThreadTaskRunnerCount(); |
| + } |
| + |
| + ~MainThreadPendingHighPriorityTaskRunner() |
| { |
| + Scheduler* scheduler = Scheduler::shared(); |
| + if (!scheduler) |
| + return; |
| + Scheduler::shared()->decrementMainThreadTaskRunnerCount(); |
| } |
| // WebThread::Task implementation. |
| virtual void run() OVERRIDE |
| { |
| - TRACE_EVENT1("blink", "MainThreadIdleTaskAdapter::run", "allottedTime", m_allottedTimeMs); |
| - m_idleTask(m_allottedTimeMs); |
| + Scheduler* scheduler = Scheduler::shared(); |
|
eseidel
2014/08/11 17:02:36
When can this happen? This feels like it should b
alexclarke
2014/08/12 11:37:02
Because a posted MainThreadPendingHighPriorityTask
|
| + if (!scheduler) |
| + return; |
| + scheduler->runHighPriorityTasks(); |
| } |
| - |
| -private: |
| - Scheduler::IdleTask m_idleTask; |
| - double m_allottedTimeMs; |
| }; |
| -} |
| +class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { |
| +public: |
| + MainThreadPendingTaskRunner( |
| + const Scheduler::Task& task, const TraceLocation& location) |
| + : m_task(task) |
| + , m_location(location) |
| + { |
| + ASSERT(Scheduler::shared()); |
| + Scheduler::shared()->incrementMainThreadTaskRunnerCount(); |
| + } |
| + |
| + ~MainThreadPendingTaskRunner() |
| + { |
| + Scheduler* scheduler = Scheduler::shared(); |
| + if (!scheduler) |
|
eseidel
2014/08/11 17:02:36
Feels like we should flush the tasks before shut-d
alexclarke
2014/08/12 11:37:03
We flush what we can (high priority tasks) but sin
|
| + return; |
| + Scheduler::shared()->decrementMainThreadTaskRunnerCount(); |
| + } |
| + |
| + // WebThread::Task implementation. |
| + virtual void run() OVERRIDE |
| + { |
| + TRACE_EVENT2("blink", "MainThreadPendingTaskRunner::run", |
|
eseidel
2014/08/11 17:02:36
Currious there is a trace here but not the other?
alexclarke
2014/08/12 11:37:02
Because Scheduler::TracedTask::run() does that for
|
| + "src_file", m_location.fileName(), |
| + "src_func", m_location.functionName()); |
| + Scheduler* scheduler = Scheduler::shared(); |
| + if (scheduler) |
| + Scheduler::shared()->runHighPriorityTasks(); |
| + m_task(); |
|
eseidel
2014/08/11 17:02:36
Why would we want to run this if !scheduler?
alexclarke
2014/08/12 11:37:02
Because this is the existing behaviour but we've a
|
| + } |
| + |
| + Scheduler::Task m_task; |
| + TraceLocation m_location; |
| +}; |
| Scheduler* Scheduler::s_sharedScheduler = nullptr; |
| @@ -80,48 +124,103 @@ Scheduler* Scheduler::shared() |
| Scheduler::Scheduler() |
| : m_mainThread(blink::Platform::current()->currentThread()) |
| , m_sharedTimerFunction(nullptr) |
| + , m_mainThreadTaskRunnerCount(0) |
| + , m_highPriotityTaskCount(0) |
| { |
| } |
| Scheduler::~Scheduler() |
| { |
| + while (shouldYieldForHighPriorityWork()) { |
| + runHighPriorityTasks(); |
| + } |
| } |
| -void Scheduler::scheduleTask(const TraceLocation& location, const Task& task) |
| -{ |
| - m_mainThread->postTask(new MainThreadTaskAdapter(location, task)); |
| -} |
| - |
| -void Scheduler::scheduleIdleTask(const IdleTask& idleTask) |
| +void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask) |
| { |
| // TODO: send a real allottedTime here. |
| - m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0)); |
| + m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)); |
| } |
| void Scheduler::postTask(const TraceLocation& location, const Task& task) |
| { |
| - scheduleTask(location, task); |
| + m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); |
| } |
| void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
| { |
| - scheduleTask(location, task); |
| + Locker<Mutex> lock(m_pendingTasksMutex); |
| + m_pendingInputTasks.append(TracedTask(task, location)); |
| + atomicIncrement(&m_highPriotityTaskCount); |
| + maybePostMainThreadPendingHighPriorityTaskRunner(); |
| } |
| void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task) |
| { |
| - scheduleTask(location, task); |
| + Locker<Mutex> lock(m_pendingTasksMutex); |
| + m_pendingCompositorTasks.append(TracedTask(task, location)); |
| + atomicIncrement(&m_highPriotityTaskCount); |
| + maybePostMainThreadPendingHighPriorityTaskRunner(); |
| } |
| -void Scheduler::postIdleTask(const IdleTask& idleTask) |
| +void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idleTask) |
| { |
| - scheduleIdleTask(idleTask); |
| + scheduleIdleTask(location, idleTask); |
| } |
| void Scheduler::tickSharedTimer() |
| { |
| TRACE_EVENT0("blink", "Scheduler::tickSharedTimer"); |
| + |
| + // Run any high priority tasks that are queued up, otherwise the blink timers will yield immediately. |
| + runHighPriorityTasks(); |
| m_sharedTimerFunction(); |
| + |
| + // The blink timers may have just yielded, so run any high priority tasks that where queued up |
| + // while the blink timers were executing. |
| + runHighPriorityTasks(); |
| +} |
| + |
| +void Scheduler::runHighPriorityTasks() |
| +{ |
| + TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks"); |
| + |
| + m_pendingTasksMutex.lock(); |
| + Deque<TracedTask>& inputTasks = m_pendingInputTasks.swapBuffers(); |
|
eseidel
2014/08/11 17:02:36
This is kinda neat.
alexclarke
2014/08/12 11:37:02
Acknowledged.
|
| + Deque<TracedTask>& compositorTasks = m_pendingCompositorTasks.swapBuffers(); |
| + m_pendingTasksMutex.unlock(); |
| + |
| + for (;;) { |
| + if (!inputTasks.isEmpty()) { |
| + inputTasks.takeFirst().run(); |
| + atomicDecrement(&m_highPriotityTaskCount); |
| + continue; |
| + } |
| + |
| + if (compositorTasks.isEmpty()) |
| + break; |
| + compositorTasks.takeFirst().run(); |
| + atomicDecrement(&m_highPriotityTaskCount); |
| + } |
| +} |
| + |
| +void Scheduler::incrementMainThreadTaskRunnerCount() |
| +{ |
| + atomicIncrement(&m_mainThreadTaskRunnerCount); |
| +} |
| + |
| +void Scheduler::decrementMainThreadTaskRunnerCount() |
| +{ |
| + atomicDecrement(&m_mainThreadTaskRunnerCount); |
| +} |
| + |
| +void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() |
| +{ |
| + // Only post a task if there isn't a task already in flight. |
| + if (acquireLoad(&m_mainThreadTaskRunnerCount)) |
| + return; |
| + |
| + m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); |
| } |
| void Scheduler::sharedTimerAdapter() |
| @@ -147,7 +246,15 @@ void Scheduler::stopSharedTimer() |
| bool Scheduler::shouldYieldForHighPriorityWork() |
| { |
| - return false; |
| + return acquireLoad(&m_highPriotityTaskCount) != 0; |
|
eseidel
2014/08/11 17:02:36
Is it concerning that this is being called often?
alexclarke
2014/08/12 11:37:02
Ultimately if we refactor all the blink timers we
|
| +} |
| + |
| +void Scheduler::TracedTask::run() |
| +{ |
| + TRACE_EVENT2("blink", "TracedTask::run", |
| + "src_file", m_location.fileName(), |
| + "src_func", m_location.functionName()); |
| + m_task(); |
| } |
| } // namespace blink |