Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "platform/scheduler/Scheduler.h" | 6 #include "platform/scheduler/Scheduler.h" |
| 7 | 7 |
| 8 #include "platform/PlatformThreadData.h" | 8 #include "platform/PlatformThreadData.h" |
| 9 #include "platform/Task.h" | 9 #include "platform/Task.h" |
| 10 #include "platform/ThreadTimers.h" | 10 #include "platform/ThreadTimers.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); | 66 scheduler->swapQueuesRunPendingTasksAndAllowHighPriorityTaskRunnerPostin g(); |
| 67 } | 67 } |
| 68 }; | 68 }; |
| 69 | 69 |
| 70 | 70 |
| 71 // Can be created from any thread. | 71 // Can be created from any thread. |
| 72 // Note if the scheduler gets shutdown, this may be run after. | 72 // Note if the scheduler gets shutdown, this may be run after. |
| 73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { | 73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task { |
| 74 public: | 74 public: |
| 75 MainThreadPendingTaskRunner( | 75 MainThreadPendingTaskRunner( |
| 76 const Scheduler::Task& task, const TraceLocation& location) | 76 const Scheduler::Task& task, const TraceLocation& location, const char* traceName, int flowTraceID) |
| 77 : m_task(task, location) | 77 : m_task(task, location, traceName, flowTraceID) |
| 78 { | 78 { |
| 79 ASSERT(Scheduler::shared()); | 79 ASSERT(Scheduler::shared()); |
| 80 } | 80 } |
| 81 | 81 |
| 82 // WebThread::Task implementation. | 82 // WebThread::Task implementation. |
| 83 virtual void run() OVERRIDE | 83 virtual void run() OVERRIDE |
| 84 { | 84 { |
| 85 Scheduler* scheduler = Scheduler::shared(); | 85 Scheduler* scheduler = Scheduler::shared(); |
| 86 // FIXME: This check should't be necessary, tasks should not outlive bli nk. | 86 // FIXME: This check should't be necessary, tasks should not outlive bli nk. |
| 87 ASSERT(scheduler); | 87 ASSERT(scheduler); |
| 88 if (scheduler) | 88 if (scheduler) |
| 89 Scheduler::shared()->swapQueuesAndRunPendingTasks(); | 89 Scheduler::shared()->swapQueuesAndRunPendingTasks(); |
| 90 m_task.run(); | 90 m_task.run(); |
| 91 } | 91 } |
| 92 | 92 |
| 93 Scheduler::TracedTask m_task; | 93 TracedTask m_task; |
| 94 }; | 94 }; |
| 95 | 95 |
| 96 Scheduler* Scheduler::s_sharedScheduler = nullptr; | 96 Scheduler* Scheduler::s_sharedScheduler = nullptr; |
| 97 | 97 |
| 98 void Scheduler::initializeOnMainThread() | 98 void Scheduler::initializeOnMainThread() |
| 99 { | 99 { |
| 100 s_sharedScheduler = new Scheduler(); | 100 s_sharedScheduler = new Scheduler(); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void Scheduler::shutdown() | 103 void Scheduler::shutdown() |
| 104 { | 104 { |
| 105 delete s_sharedScheduler; | 105 delete s_sharedScheduler; |
| 106 s_sharedScheduler = nullptr; | 106 s_sharedScheduler = nullptr; |
| 107 } | 107 } |
| 108 | 108 |
| 109 Scheduler* Scheduler::shared() | 109 Scheduler* Scheduler::shared() |
| 110 { | 110 { |
| 111 return s_sharedScheduler; | 111 return s_sharedScheduler; |
| 112 } | 112 } |
| 113 | 113 |
| 114 Scheduler::Scheduler() | 114 Scheduler::Scheduler() |
| 115 : m_sharedTimerFunction(nullptr) | 115 : m_sharedTimerFunction(nullptr) |
| 116 , m_mainThread(blink::Platform::current()->currentThread()) | 116 , m_mainThread(blink::Platform::current()->currentThread()) |
| 117 , m_highPriorityTaskCount(0) | 117 , m_highPriorityTaskCount(0) |
| 118 // flow trace ID begins as the 'this' pointer to help ensure different sched uler | |
| 119 // instances don't generate identical IDs | |
| 120 , m_nextFlowTraceID(static_cast<int>(reinterpret_cast<intptr_t>(this))) | |
| 118 , m_highPriorityTaskRunnerPosted(false) | 121 , m_highPriorityTaskRunnerPosted(false) |
| 119 { | 122 { |
| 120 } | 123 } |
| 121 | 124 |
| 122 Scheduler::~Scheduler() | 125 Scheduler::~Scheduler() |
| 123 { | 126 { |
| 124 while (hasPendingHighPriorityWork()) { | 127 while (hasPendingHighPriorityWork()) { |
| 125 swapQueuesAndRunPendingTasks(); | 128 swapQueuesAndRunPendingTasks(); |
| 126 } | 129 } |
| 127 } | 130 } |
| 128 | 131 |
| 132 int Scheduler::generateFlowTraceID() | |
| 133 { | |
| 134 return atomicIncrement(&m_nextFlowTraceID); | |
| 135 } | |
| 136 | |
| 129 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask) | 137 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask) |
| 130 { | 138 { |
| 131 // TODO: send a real allottedTime here. | 139 // TODO: send a real allottedTime here. |
| 132 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ; | 140 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location)) ; |
| 133 } | 141 } |
| 134 | 142 |
| 143 void Scheduler::postHighPriorityTaskInternal(const TraceLocation& location, cons t Task& task, const char * traceName) | |
| 144 { | |
| 145 Locker<Mutex> lock(m_pendingTasksMutex); | |
| 146 | |
| 147 TracedTask tracedTask = TracedTask(task, location, traceName, generateFlowTr aceID()); | |
|
alexclarke
2014/09/01 11:24:20
How about:
m_pendingHighPriorityTasks.append(Trac
picksi1
2014/09/01 13:33:48
In general I like to break complex lines down to a
| |
| 148 m_pendingHighPriorityTasks.append(tracedTask); | |
| 149 atomicIncrement(&m_highPriorityTaskCount); | |
| 150 maybePostMainThreadPendingHighPriorityTaskRunner(); | |
| 151 } | |
| 152 | |
| 135 void Scheduler::postTask(const TraceLocation& location, const Task& task) | 153 void Scheduler::postTask(const TraceLocation& location, const Task& task) |
| 136 { | 154 { |
| 137 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location)); | 155 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location, "Sche duler::MainThreadTask", generateFlowTraceID())); |
| 138 } | 156 } |
| 139 | 157 |
| 140 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) | 158 void Scheduler::postInputTask(const TraceLocation& location, const Task& task) |
| 141 { | 159 { |
| 142 Locker<Mutex> lock(m_pendingTasksMutex); | 160 postHighPriorityTaskInternal(location, task, "Scheduler::InputTask"); |
| 143 m_pendingHighPriorityTasks.append(TracedTask(task, location)); | |
| 144 atomicIncrement(&m_highPriorityTaskCount); | |
| 145 maybePostMainThreadPendingHighPriorityTaskRunner(); | |
| 146 } | 161 } |
| 147 | 162 |
| 148 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) | 163 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& ta sk) |
| 149 { | 164 { |
| 150 Locker<Mutex> lock(m_pendingTasksMutex); | 165 postHighPriorityTaskInternal(location, task, "Scheduler::CompositorTask"); |
| 151 m_pendingHighPriorityTasks.append(TracedTask(task, location)); | |
| 152 atomicIncrement(&m_highPriorityTaskCount); | |
| 153 maybePostMainThreadPendingHighPriorityTaskRunner(); | |
| 154 } | 166 } |
| 155 | 167 |
| 156 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() | 168 void Scheduler::maybePostMainThreadPendingHighPriorityTaskRunner() |
| 157 { | 169 { |
| 158 ASSERT(m_pendingTasksMutex.locked()); | 170 ASSERT(m_pendingTasksMutex.locked()); |
| 159 if (m_highPriorityTaskRunnerPosted) | 171 if (m_highPriorityTaskRunnerPosted) |
| 160 return; | 172 return; |
| 161 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); | 173 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner()); |
| 162 m_highPriorityTaskRunnerPosted = true; | 174 m_highPriorityTaskRunnerPosted = true; |
| 163 } | 175 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 bool Scheduler::hasPendingHighPriorityWork() const | 261 bool Scheduler::hasPendingHighPriorityWork() const |
| 250 { | 262 { |
| 251 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by | 263 // This method is expected to be run on the main thread, but the high priori ty tasks will be posted by |
| 252 // other threads. We could use locks here, but this function is (sometimes) called a lot by | 264 // other threads. We could use locks here, but this function is (sometimes) called a lot by |
| 253 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which | 265 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + bar rier loads here which |
| 254 // should be cheaper. | 266 // should be cheaper. |
| 255 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. | 267 // NOTE it's possible the barrier read is overkill here, since delayed yield ing isn't a big deal. |
| 256 return acquireLoad(&m_highPriorityTaskCount) != 0; | 268 return acquireLoad(&m_highPriorityTaskCount) != 0; |
| 257 } | 269 } |
| 258 | 270 |
| 259 void Scheduler::TracedTask::run() | |
| 260 { | |
| 261 TRACE_EVENT2("blink", "TracedTask::run", | |
| 262 "src_file", m_location.fileName(), | |
| 263 "src_func", m_location.functionName()); | |
| 264 m_task(); | |
| 265 } | |
| 266 | |
| 267 } // namespace blink | 271 } // namespace blink |
| OLD | NEW |