Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / scheduler / Scheduler.cpp
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.
4
5 #include "config.h"
6 #include "platform/scheduler/Scheduler.h"
7
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"
15
16
17 namespace blink {
18
19 namespace {
20
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 {
24 public:
25     MainThreadIdleTaskAdapter(const Scheduler::IdleTask& idleTask, double allottedTimeMs, const TraceLocation& location)
26         : m_idleTask(idleTask)
27         , m_allottedTimeMs(allottedTimeMs)
28         , m_location(location)
29     {
30     }
31
32     // WebThread::Task implementation.
33     virtual void run() OVERRIDE
34     {
35         TRACE_EVENT2("blink", "MainThreadIdleTaskAdapter::run",
36             "src_file", m_location.fileName(),
37             "src_func", m_location.functionName());
38         m_idleTask(m_allottedTimeMs);
39     }
40
41 private:
42     Scheduler::IdleTask m_idleTask;
43     double m_allottedTimeMs;
44     TraceLocation m_location;
45 };
46
47 } // namespace
48
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 {
52 public:
53     MainThreadPendingHighPriorityTaskRunner()
54     {
55         ASSERT(Scheduler::shared());
56     }
57
58     // WebThread::Task implementation.
59     virtual void run() OVERRIDE
60     {
61         Scheduler* scheduler = Scheduler::shared();
62         // FIXME: This check should't be necessary, tasks should not outlive blink.
63         ASSERT(scheduler);
64         if (!scheduler)
65             return;
66         scheduler->runHighPriorityTasks();
67     }
68 };
69
70
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 {
74 public:
75     MainThreadPendingTaskRunner(
76         const Scheduler::Task& task, const TraceLocation& location)
77         : m_task(task, location)
78     {
79         ASSERT(Scheduler::shared());
80     }
81
82     // WebThread::Task implementation.
83     virtual void run() OVERRIDE
84     {
85         Scheduler* scheduler = Scheduler::shared();
86         // FIXME: This check should't be necessary, tasks should not outlive blink.
87         ASSERT(scheduler);
88         if (scheduler)
89             Scheduler::shared()->runHighPriorityTasks();
90         m_task.run();
91     }
92
93     Scheduler::TracedTask m_task;
94 };
95
96 Scheduler* Scheduler::s_sharedScheduler = nullptr;
97
98 void Scheduler::initializeOnMainThread()
99 {
100     s_sharedScheduler = new Scheduler();
101 }
102
103 void Scheduler::shutdown()
104 {
105     delete s_sharedScheduler;
106     s_sharedScheduler = nullptr;
107 }
108
109 Scheduler* Scheduler::shared()
110 {
111     return s_sharedScheduler;
112 }
113
114 Scheduler::Scheduler()
115     : m_sharedTimerFunction(nullptr)
116     , m_mainThread(blink::Platform::current()->currentThread())
117     , m_highPriorityTaskCount(0)
118 {
119 }
120
121 Scheduler::~Scheduler()
122 {
123     while (hasPendingHighPriorityWork()) {
124         runHighPriorityTasks();
125     }
126 }
127
128 void Scheduler::scheduleIdleTask(const TraceLocation& location, const IdleTask& idleTask)
129 {
130     // TODO: send a real allottedTime here.
131     m_mainThread->postTask(new MainThreadIdleTaskAdapter(idleTask, 0, location));
132 }
133
134 void Scheduler::postTask(const TraceLocation& location, const Task& task)
135 {
136     m_mainThread->postTask(new MainThreadPendingTaskRunner(task, location));
137 }
138
139 void Scheduler::postInputTask(const TraceLocation& location, const Task& task)
140 {
141     Locker<Mutex> lock(m_pendingTasksMutex);
142     m_pendingInputTasks.append(TracedTask(task, location));
143     atomicIncrement(&m_highPriorityTaskCount);
144     m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
145 }
146
147 void Scheduler::postCompositorTask(const TraceLocation& location, const Task& task)
148 {
149     Locker<Mutex> lock(m_pendingTasksMutex);
150     m_pendingCompositorTasks.append(TracedTask(task, location));
151     atomicIncrement(&m_highPriorityTaskCount);
152     m_mainThread->postTask(new MainThreadPendingHighPriorityTaskRunner());
153 }
154
155 void Scheduler::postIdleTask(const TraceLocation& location, const IdleTask& idleTask)
156 {
157     scheduleIdleTask(location, idleTask);
158 }
159
160 void Scheduler::tickSharedTimer()
161 {
162     TRACE_EVENT0("blink", "Scheduler::tickSharedTimer");
163
164     // Run any high priority tasks that are queued up, otherwise the blink timers will yield immediately.
165     runHighPriorityTasks();
166     m_sharedTimerFunction();
167
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();
171 }
172
173 void Scheduler::runHighPriorityTasks()
174 {
175     ASSERT(isMainThread());
176     TRACE_EVENT0("blink", "Scheduler::runHighPriorityTasks");
177
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();
184
185     int highPriorityTasksExecuted = 0;
186     while (!inputTasks.isEmpty()) {
187         inputTasks.takeFirst().run();
188         highPriorityTasksExecuted++;
189     }
190
191     while (!compositorTasks.isEmpty()) {
192         compositorTasks.takeFirst().run();
193         highPriorityTasksExecuted++;
194     }
195
196     int highPriorityTaskCount = atomicSubtract(&m_highPriorityTaskCount, highPriorityTasksExecuted);
197     ASSERT_UNUSED(highPriorityTaskCount, highPriorityTaskCount >= 0);
198 }
199
200 void Scheduler::sharedTimerAdapter()
201 {
202     shared()->tickSharedTimer();
203 }
204
205 void Scheduler::setSharedTimerFiredFunction(void (*function)())
206 {
207     m_sharedTimerFunction = function;
208     blink::Platform::current()->setSharedTimerFiredFunction(function ? &Scheduler::sharedTimerAdapter : nullptr);
209 }
210
211 void Scheduler::setSharedTimerFireInterval(double interval)
212 {
213     blink::Platform::current()->setSharedTimerFireInterval(interval);
214 }
215
216 void Scheduler::stopSharedTimer()
217 {
218     blink::Platform::current()->stopSharedTimer();
219 }
220
221 bool Scheduler::shouldYieldForHighPriorityWork() const
222 {
223     return hasPendingHighPriorityWork();
224 }
225
226 bool Scheduler::hasPendingHighPriorityWork() const
227 {
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;
234 }
235
236 void Scheduler::TracedTask::run()
237 {
238     TRACE_EVENT2("blink", "TracedTask::run",
239         "src_file", m_location.fileName(),
240         "src_func", m_location.functionName());
241     m_task();
242 }
243
244 } // namespace blink