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
3 // found in the LICENSE file.
6 #include "platform/scheduler/Scheduler.h"
8 #include "platform/PlatformThreadData.h"
9 #include "platform/Task.h"
10 #include "platform/ThreadTimers.h"
11 #include "platform/TraceEvent.h"
12 #include "public/platform/Platform.h"
13 #include "wtf/MainThread.h"
14 #include "wtf/ThreadingPrimitives.h"
21 // Can be created from any thread.
22 // Note if the scheduler gets shutdown, this may be run after.
23 class MainThreadIdleTaskAdapter : public WebThread::Task {
25 MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allottedTimeMs, const TraceLocation& location)
26 : m_idleTask(idleTask)
27 , m_allottedTimeMs(allottedTimeMs)
28 , m_location(location)
32 // WebThread::Task implementation.
33 virtual void run() OVERRIDE
35 TRACE_EVENT2("blink", "MainThreadIdleTaskAdapter::run",
36 "src_file", m_location.fileName(),
37 "src_func", m_location.functionName());
38 m_idleTask(m_allottedTimeMs);
42 Scheduler::IdleTask m_idleTask;
43 double m_allottedTimeMs;
44 TraceLocation m_location;
49 // Typically only created from compositor or render threads.
50 // Note if the scheduler gets shutdown, this may be run after.
51 class Scheduler::MainThreadPendingHighPriorityTaskRunner : public WebThread::Task {
53 MainThreadPendingHighPriorityTaskRunner()
55 ASSERT(Scheduler::shared());
58 // WebThread::Task implementation.
59 virtual void run() OVERRIDE
61 Scheduler* scheduler = Scheduler::shared();
62 // FIXME: This check should't be necessary, tasks should not outlive blink.
66 scheduler->runHighPriorityTasks();
71 // Can be created from any thread.
72 // Note if the scheduler gets shutdown, this may be run after.
73 class Scheduler::MainThreadPendingTaskRunner : public WebThread::Task {
75 MainThreadPendingTaskRunner(
76 const Scheduler::Task& task, const TraceLocation& location)
77 : m_task(task, location)
79 ASSERT(Scheduler::shared());
82 // WebThread::Task implementation.
83 virtual void run() OVERRIDE
85 Scheduler* scheduler = Scheduler::shared();
86 // FIXME: This check should't be necessary, tasks should not outlive blink.
89 Scheduler::shared()->runHighPriorityTasks();
93 Scheduler::TracedTask m_task;
96 Scheduler* Scheduler::s_sharedScheduler = nullptr;
98 void Scheduler::initializeOnMainThread()
100 s_sharedScheduler = new Scheduler();
103 void Scheduler::shutdown()
105 delete s_sharedScheduler;
106 s_sharedScheduler = nullptr;
109 Scheduler* Scheduler::shared()
111 return s_sharedScheduler;
114 Scheduler::Scheduler()
115 : m_sharedTimerFunction(nullptr)
116 , m_mainThread(blink::Platform::current()->currentThread())
117 , m_highPriorityTaskCount(0)
121 Scheduler::~Scheduler()
123 while (hasPendingHighPriorityWork()) {
124 runHighPriorityTasks();
128 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask)
130 // TODO: send a real allottedTime here.
131 m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location));
134 void Scheduler::postTask(const TraceLocation& location, const Task& task)
136 m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
139 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
141 Locker<Mutex> lock(m_pendingTasksMutex);
142 m_pendingInputTasks.append(TracedTask(task, location));
143 atomicIncrement(&m_highPriorityTaskCount);
144 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
147 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task)
149 Locker<Mutex> lock(m_pendingTasksMutex);
150 m_pendingCompositorTasks.append(TracedTask(task, location));
151 atomicIncrement(&m_highPriorityTaskCount);
152 m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
155 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idleTask)
157 scheduleIdleTask(location, idleTask);
160 void Scheduler::tickSharedTimer()
162 TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
164 // Run any high priority tasks that are queued up, otherwise the blink timers will yield immediately.
165 runHighPriorityTasks();
166 m_sharedTimerFunction();
168 // The blink timers may have just yielded, so run any high priority tasks that where queued up
169 // while the blink timers were executing.
170 runHighPriorityTasks();
173 void Scheduler::runHighPriorityTasks()
175 ASSERT(isMainThread());
176 TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks");
178 // These locks guard against another thread posting input or compositor tasks while we swap the buffers.
179 // One the buffers have been swapped we can safely access the returned deque without having to lock.
180 m_pendingTasksMutex.lock();
181 Deque<TracedTask>& inputTasks = m_pendingInputTasks.swapBuffers();
182 Deque<TracedTask>& compositorTasks = m_pendingCompositorTasks.swapBuffers();
183 m_pendingTasksMutex.unlock();
185 int highPriorityTasksExecuted = 0;
186 while (!inputTasks.isEmpty()) {
187 inputTasks.takeFirst().run();
188 highPriorityTasksExecuted++;
191 while (!compositorTasks.isEmpty()) {
192 compositorTasks.takeFirst().run();
193 highPriorityTasksExecuted++;
196 int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPriorityTasksExecuted);
197 ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
200 void Scheduler::sharedTimerAdapter()
202 shared()->tickSharedTimer();
205 void Scheduler::setSharedTimerFiredFunction(void (*function)())
207 m_sharedTimerFunction = function;
208 blink::Platform::current()->setSharedTimerFiredFunction(function ? &Scheduler::sharedTimerAdapter : nullptr);
211 void Scheduler::setSharedTimerFireInterval(double interval)
213 blink::Platform::current()->setSharedTimerFireInterval(interval);
216 void Scheduler::stopSharedTimer()
218 blink::Platform::current()->stopSharedTimer();
221 bool Scheduler::shouldYieldForHighPriorityWork() const
223 return hasPendingHighPriorityWork();
226 bool Scheduler::hasPendingHighPriorityWork() const
228 // This method is expected to be run on the main thread, but the high priority tasks will be posted by
229 // other threads. We could use locks here, but this function is (sometimes) called a lot by
230 // ThreadTimers::sharedTimerFiredInternal so we decided to use atomics + barrier loads here which
231 // should be cheaper.
232 // NOTE it's possible the barrier read is overkill here, since delayed yielding isn't a big deal.
233 return acquireLoad(&m_highPriorityTaskCount) != 0;
236 void Scheduler::TracedTask::run()
238 TRACE_EVENT2("blink", "TracedTask::run",
239 "src_file", m_location.fileName(),
240 "src_func", m_location.functionName());