OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/renderer/raster_worker_pool.h" | 5 #include "content/renderer/raster_worker_pool.h" |
6 | 6 |
7 #include "base/strings/stringprintf.h" | 7 #include "base/strings/stringprintf.h" |
| 8 #include "base/threading/thread_restrictions.h" |
| 9 #include "base/trace_event/trace_event.h" |
8 | 10 |
9 namespace content { | 11 namespace content { |
10 | 12 |
11 // A sequenced task runner which posts tasks to a RasterWorkerPool. | 13 // A sequenced task runner which posts tasks to a RasterWorkerPool. |
12 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner | 14 class RasterWorkerPool::RasterWorkerPoolSequencedTaskRunner |
13 : public base::SequencedTaskRunner { | 15 : public base::SequencedTaskRunner { |
14 public: | 16 public: |
15 RasterWorkerPoolSequencedTaskRunner(cc::TaskGraphRunner* task_graph_runner) | 17 explicit RasterWorkerPoolSequencedTaskRunner( |
| 18 cc::TaskGraphRunner* task_graph_runner) |
16 : task_graph_runner_(task_graph_runner), | 19 : task_graph_runner_(task_graph_runner), |
17 namespace_token_(task_graph_runner->GetNamespaceToken()) {} | 20 namespace_token_(task_graph_runner->GetNamespaceToken()) {} |
18 | 21 |
19 // Overridden from base::TaskRunner: | 22 // Overridden from base::TaskRunner: |
20 bool PostDelayedTask(const tracked_objects::Location& from_here, | 23 bool PostDelayedTask(const tracked_objects::Location& from_here, |
21 const base::Closure& task, | 24 const base::Closure& task, |
22 base::TimeDelta delay) override { | 25 base::TimeDelta delay) override { |
23 return PostNonNestableDelayedTask(from_here, task, delay); | 26 return PostNonNestableDelayedTask(from_here, task, delay); |
24 } | 27 } |
25 bool RunsTasksOnCurrentThread() const override { return true; } | 28 bool RunsTasksOnCurrentThread() const override { return true; } |
(...skipping 30 matching lines...) Expand all Loading... |
56 return true; | 59 return true; |
57 } | 60 } |
58 | 61 |
59 private: | 62 private: |
60 ~RasterWorkerPoolSequencedTaskRunner() override { | 63 ~RasterWorkerPoolSequencedTaskRunner() override { |
61 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); | 64 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); |
62 task_graph_runner_->CollectCompletedTasks(namespace_token_, | 65 task_graph_runner_->CollectCompletedTasks(namespace_token_, |
63 &completed_tasks_); | 66 &completed_tasks_); |
64 }; | 67 }; |
65 | 68 |
66 cc::TaskGraphRunner* const task_graph_runner_; | |
67 | |
68 // Lock to exclusively access all the following members that are used to | 69 // Lock to exclusively access all the following members that are used to |
69 // implement the SequencedTaskRunner interfaces. | 70 // implement the SequencedTaskRunner interfaces. |
70 base::Lock lock_; | 71 base::Lock lock_; |
| 72 |
| 73 cc::TaskGraphRunner* task_graph_runner_; |
71 // Namespace used to schedule tasks in the task graph runner. | 74 // Namespace used to schedule tasks in the task graph runner. |
72 cc::NamespaceToken namespace_token_; | 75 cc::NamespaceToken namespace_token_; |
73 // List of tasks currently queued up for execution. | 76 // List of tasks currently queued up for execution. |
74 cc::Task::Vector tasks_; | 77 cc::Task::Vector tasks_; |
75 // Graph object used for scheduling tasks. | 78 // Graph object used for scheduling tasks. |
76 cc::TaskGraph graph_; | 79 cc::TaskGraph graph_; |
77 // Cached vector to avoid allocation when getting the list of complete | 80 // Cached vector to avoid allocation when getting the list of complete |
78 // tasks. | 81 // tasks. |
79 cc::Task::Vector completed_tasks_; | 82 cc::Task::Vector completed_tasks_; |
80 }; | 83 }; |
81 | 84 |
82 RasterWorkerPool::RasterWorkerPool() | 85 RasterWorkerPool::RasterWorkerPool() |
83 : namespace_token_(task_graph_runner_.GetNamespaceToken()) {} | 86 : namespace_token_(GetNamespaceToken()), |
| 87 has_ready_to_run_tasks_cv_(&lock_), |
| 88 has_namespaces_with_finished_running_tasks_cv_(&lock_), |
| 89 shutdown_(false) {} |
84 | 90 |
85 void RasterWorkerPool::Start( | 91 void RasterWorkerPool::Start( |
86 int num_threads, | 92 int num_threads, |
87 const base::SimpleThread::Options& thread_options) { | 93 const base::SimpleThread::Options& thread_options) { |
88 DCHECK(threads_.empty()); | 94 DCHECK(threads_.empty()); |
89 while (threads_.size() < static_cast<size_t>(num_threads)) { | 95 while (threads_.size() < static_cast<size_t>(num_threads)) { |
90 scoped_ptr<base::DelegateSimpleThread> thread( | 96 scoped_ptr<base::DelegateSimpleThread> thread( |
91 new base::DelegateSimpleThread( | 97 new base::DelegateSimpleThread( |
92 this, base::StringPrintf("CompositorTileWorker%u", | 98 this, base::StringPrintf("CompositorTileWorker%u", |
93 static_cast<unsigned>(threads_.size() + 1)) | 99 static_cast<unsigned>(threads_.size() + 1)) |
94 .c_str(), | 100 .c_str(), |
95 thread_options)); | 101 thread_options)); |
96 thread->Start(); | 102 thread->Start(); |
97 threads_.push_back(thread.Pass()); | 103 threads_.push_back(thread.Pass()); |
98 } | 104 } |
99 } | 105 } |
100 | 106 |
101 void RasterWorkerPool::Shutdown() { | 107 void RasterWorkerPool::Shutdown() { |
102 task_graph_runner_.WaitForTasksToFinishRunning(namespace_token_); | 108 WaitForTasksToFinishRunning(namespace_token_); |
103 task_graph_runner_.CollectCompletedTasks(namespace_token_, &completed_tasks_); | 109 CollectCompletedTasks(namespace_token_, &completed_tasks_); |
104 // Shutdown raster threads. | 110 // Shutdown raster threads. |
105 task_graph_runner_.Shutdown(); | 111 { |
| 112 base::AutoLock lock(lock_); |
| 113 |
| 114 DCHECK(!work_queue_.HasReadyToRunTasks()); |
| 115 DCHECK(!work_queue_.HasAnyNamespaces()); |
| 116 |
| 117 DCHECK(!shutdown_); |
| 118 shutdown_ = true; |
| 119 |
| 120 // Wake up a worker so it knows it should exit. This will cause all workers |
| 121 // to exit as each will wake up another worker before exiting. |
| 122 has_ready_to_run_tasks_cv_.Signal(); |
| 123 } |
106 while (!threads_.empty()) { | 124 while (!threads_.empty()) { |
107 threads_.back()->Join(); | 125 threads_.back()->Join(); |
108 threads_.pop_back(); | 126 threads_.pop_back(); |
109 } | 127 } |
110 } | 128 } |
111 | 129 |
112 // Overridden from base::TaskRunner: | 130 // Overridden from base::TaskRunner: |
113 bool RasterWorkerPool::PostDelayedTask( | 131 bool RasterWorkerPool::PostDelayedTask( |
114 const tracked_objects::Location& from_here, | 132 const tracked_objects::Location& from_here, |
115 const base::Closure& task, | 133 const base::Closure& task, |
116 base::TimeDelta delay) { | 134 base::TimeDelta delay) { |
117 base::AutoLock lock(lock_); | 135 base::AutoLock lock(lock_); |
118 | 136 |
119 // Remove completed tasks. | 137 // Remove completed tasks. |
120 DCHECK(completed_tasks_.empty()); | 138 DCHECK(completed_tasks_.empty()); |
121 task_graph_runner_.CollectCompletedTasks(namespace_token_, &completed_tasks_); | 139 CollectCompletedTasksWithLockAcquired(namespace_token_, &completed_tasks_); |
122 | 140 |
123 cc::Task::Vector::iterator end = std::remove_if( | 141 cc::Task::Vector::iterator end = std::remove_if( |
124 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { | 142 tasks_.begin(), tasks_.end(), [this](const scoped_refptr<cc::Task>& e) { |
125 return std::find(this->completed_tasks_.begin(), | 143 return std::find(this->completed_tasks_.begin(), |
126 this->completed_tasks_.end(), | 144 this->completed_tasks_.end(), |
127 e) != this->completed_tasks_.end(); | 145 e) != this->completed_tasks_.end(); |
128 }); | 146 }); |
129 tasks_.erase(end, tasks_.end()); | 147 tasks_.erase(end, tasks_.end()); |
130 | 148 |
131 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); | 149 tasks_.push_back(make_scoped_refptr(new ClosureTask(task))); |
132 graph_.Reset(); | 150 graph_.Reset(); |
133 for (const auto& graph_task : tasks_) | 151 for (const auto& graph_task : tasks_) |
134 graph_.nodes.push_back(cc::TaskGraph::Node(graph_task.get(), 0, 0)); | 152 graph_.nodes.push_back(cc::TaskGraph::Node(graph_task.get(), 0, 0)); |
135 | 153 |
136 task_graph_runner_.ScheduleTasks(namespace_token_, &graph_); | 154 ScheduleTasksWithLockAcquired(namespace_token_, &graph_); |
137 completed_tasks_.clear(); | 155 completed_tasks_.clear(); |
138 return true; | 156 return true; |
139 } | 157 } |
140 | 158 |
141 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { | 159 bool RasterWorkerPool::RunsTasksOnCurrentThread() const { |
142 return true; | 160 return true; |
143 } | 161 } |
144 | 162 |
145 // Overridden from base::DelegateSimpleThread::Delegate: | 163 // Overridden from base::DelegateSimpleThread::Delegate: |
146 void RasterWorkerPool::Run() { | 164 void RasterWorkerPool::Run() { |
147 task_graph_runner_.Run(); | 165 base::AutoLock lock(lock_); |
| 166 |
| 167 while (true) { |
| 168 if (!work_queue_.HasReadyToRunTasks()) { |
| 169 // Exit when shutdown is set and no more tasks are pending. |
| 170 if (shutdown_) |
| 171 break; |
| 172 |
| 173 // Wait for more tasks. |
| 174 has_ready_to_run_tasks_cv_.Wait(); |
| 175 continue; |
| 176 } |
| 177 |
| 178 RunTaskWithLockAcquired(); |
| 179 } |
| 180 |
| 181 // We noticed we should exit. Wake up the next worker so it knows it should |
| 182 // exit as well (because the Shutdown() code only signals once). |
| 183 has_ready_to_run_tasks_cv_.Signal(); |
| 184 } |
| 185 |
| 186 void RasterWorkerPool::FlushForTesting() { |
| 187 base::AutoLock lock(lock_); |
| 188 |
| 189 while (!work_queue_.HasFinishedRunningTasksInAllNamespaces()) { |
| 190 has_namespaces_with_finished_running_tasks_cv_.Wait(); |
| 191 } |
148 } | 192 } |
149 | 193 |
150 scoped_refptr<base::SequencedTaskRunner> | 194 scoped_refptr<base::SequencedTaskRunner> |
151 RasterWorkerPool::CreateSequencedTaskRunner() { | 195 RasterWorkerPool::CreateSequencedTaskRunner() { |
152 return new RasterWorkerPoolSequencedTaskRunner(&task_graph_runner_); | 196 return new RasterWorkerPoolSequencedTaskRunner(this); |
153 } | 197 } |
154 | 198 |
155 RasterWorkerPool::~RasterWorkerPool() {} | 199 RasterWorkerPool::~RasterWorkerPool() {} |
156 | 200 |
| 201 cc::NamespaceToken RasterWorkerPool::GetNamespaceToken() { |
| 202 base::AutoLock lock(lock_); |
| 203 return work_queue_.GetNamespaceToken(); |
| 204 } |
| 205 |
| 206 void RasterWorkerPool::ScheduleTasks(cc::NamespaceToken token, |
| 207 cc::TaskGraph* graph) { |
| 208 TRACE_EVENT2("cc", "RasterWorkerPool::ScheduleTasks", "num_nodes", |
| 209 graph->nodes.size(), "num_edges", graph->edges.size()); |
| 210 { |
| 211 base::AutoLock lock(lock_); |
| 212 ScheduleTasksWithLockAcquired(token, graph); |
| 213 } |
| 214 } |
| 215 |
| 216 void RasterWorkerPool::ScheduleTasksWithLockAcquired(cc::NamespaceToken token, |
| 217 cc::TaskGraph* graph) { |
| 218 DCHECK(token.IsValid()); |
| 219 DCHECK(!cc::TaskGraphWorkQueue::DependencyMismatch(graph)); |
| 220 DCHECK(!shutdown_); |
| 221 |
| 222 work_queue_.ScheduleTasks(token, graph); |
| 223 |
| 224 // If there is more work available, wake up worker thread. |
| 225 if (work_queue_.HasReadyToRunTasks()) |
| 226 has_ready_to_run_tasks_cv_.Signal(); |
| 227 } |
| 228 |
| 229 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) { |
| 230 TRACE_EVENT0("cc", "RasterWorkerPool::WaitForTasksToFinishRunning"); |
| 231 |
| 232 DCHECK(token.IsValid()); |
| 233 |
| 234 { |
| 235 base::AutoLock lock(lock_); |
| 236 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 237 |
| 238 auto* task_namespace = work_queue_.GetNamespaceForToken(token); |
| 239 |
| 240 if (!task_namespace) |
| 241 return; |
| 242 |
| 243 while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace)) |
| 244 has_namespaces_with_finished_running_tasks_cv_.Wait(); |
| 245 |
| 246 // There may be other namespaces that have finished running tasks, so wake |
| 247 // up another origin thread. |
| 248 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| 249 } |
| 250 } |
| 251 |
| 252 void RasterWorkerPool::CollectCompletedTasks( |
| 253 cc::NamespaceToken token, |
| 254 cc::Task::Vector* completed_tasks) { |
| 255 TRACE_EVENT0("cc", "RasterWorkerPool::CollectCompletedTasks"); |
| 256 |
| 257 { |
| 258 base::AutoLock lock(lock_); |
| 259 CollectCompletedTasksWithLockAcquired(token, completed_tasks); |
| 260 } |
| 261 } |
| 262 |
| 263 void RasterWorkerPool::CollectCompletedTasksWithLockAcquired( |
| 264 cc::NamespaceToken token, |
| 265 cc::Task::Vector* completed_tasks) { |
| 266 DCHECK(token.IsValid()); |
| 267 work_queue_.CollectCompletedTasks(token, completed_tasks); |
| 268 } |
| 269 |
| 270 void RasterWorkerPool::RunTaskWithLockAcquired() { |
| 271 TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask"); |
| 272 |
| 273 lock_.AssertAcquired(); |
| 274 |
| 275 auto prioritized_task = work_queue_.GetNextTaskToRun(); |
| 276 cc::Task* task = prioritized_task.task; |
| 277 |
| 278 // There may be more work available, so wake up another worker thread. |
| 279 has_ready_to_run_tasks_cv_.Signal(); |
| 280 |
| 281 // Call WillRun() before releasing |lock_| and running task. |
| 282 task->WillRun(); |
| 283 |
| 284 { |
| 285 base::AutoUnlock unlock(lock_); |
| 286 |
| 287 task->RunOnWorkerThread(); |
| 288 } |
| 289 |
| 290 // This will mark task as finished running. |
| 291 task->DidRun(); |
| 292 |
| 293 work_queue_.CompleteTask(prioritized_task); |
| 294 |
| 295 // If namespace has finished running all tasks, wake up origin thread. |
| 296 if (work_queue_.HasFinishedRunningTasksInNamespace( |
| 297 prioritized_task.task_namespace)) |
| 298 has_namespaces_with_finished_running_tasks_cv_.Signal(); |
| 299 } |
| 300 |
157 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) | 301 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure) |
158 : closure_(closure) {} | 302 : closure_(closure) {} |
159 | 303 |
160 // Overridden from cc::Task: | 304 // Overridden from cc::Task: |
161 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { | 305 void RasterWorkerPool::ClosureTask::RunOnWorkerThread() { |
162 closure_.Run(); | 306 closure_.Run(); |
163 closure_.Reset(); | 307 closure_.Reset(); |
164 }; | 308 } |
165 | 309 |
166 RasterWorkerPool::ClosureTask::~ClosureTask() {} | 310 RasterWorkerPool::ClosureTask::~ClosureTask() {} |
167 | 311 |
168 } // namespace content | 312 } // namespace content |
OLD | NEW |