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 "platform/scheduler/base/task_queue_manager.h" | 5 #include "platform/scheduler/base/task_queue_manager.h" |
6 | 6 |
7 #include <queue> | 7 #include <queue> |
8 #include <set> | 8 #include <set> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 } | 51 } |
52 | 52 |
53 TaskQueueManager::TaskQueueManager( | 53 TaskQueueManager::TaskQueueManager( |
54 scoped_refptr<TaskQueueManagerDelegate> delegate, | 54 scoped_refptr<TaskQueueManagerDelegate> delegate, |
55 const char* tracing_category, | 55 const char* tracing_category, |
56 const char* disabled_by_default_tracing_category, | 56 const char* disabled_by_default_tracing_category, |
57 const char* disabled_by_default_verbose_tracing_category) | 57 const char* disabled_by_default_verbose_tracing_category) |
58 : real_time_domain_(new RealTimeDomain(tracing_category)), | 58 : real_time_domain_(new RealTimeDomain(tracing_category)), |
59 delegate_(delegate), | 59 delegate_(delegate), |
60 task_was_run_on_quiescence_monitored_queue_(false), | 60 task_was_run_on_quiescence_monitored_queue_(false), |
61 other_thread_pending_wakeup_(false), | 61 do_work_pending_lock_(), // NOTE this calls the constructor! |
Sami
2016/12/07 16:13:42
Is this gonna work? This[1] says spinlocks can onl
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Acknowledged.
| |
62 do_work_running_count_(0), | |
63 immediate_do_work_posted_count_(0), | |
64 is_nested_(false), | |
65 record_task_delay_histograms_(true), | |
62 work_batch_size_(1), | 66 work_batch_size_(1), |
63 task_count_(0), | 67 task_count_(0), |
64 tracing_category_(tracing_category), | 68 tracing_category_(tracing_category), |
65 disabled_by_default_tracing_category_( | 69 disabled_by_default_tracing_category_( |
66 disabled_by_default_tracing_category), | 70 disabled_by_default_tracing_category), |
67 disabled_by_default_verbose_tracing_category_( | 71 disabled_by_default_verbose_tracing_category_( |
68 disabled_by_default_verbose_tracing_category), | 72 disabled_by_default_verbose_tracing_category), |
69 currently_executing_task_queue_(nullptr), | 73 currently_executing_task_queue_(nullptr), |
70 observer_(nullptr), | 74 observer_(nullptr), |
71 deletion_sentinel_(new DeletionSentinel()), | 75 deletion_sentinel_(new DeletionSentinel()), |
72 weak_factory_(this) { | 76 weak_factory_(this) { |
73 DCHECK(delegate->RunsTasksOnCurrentThread()); | 77 DCHECK(delegate->RunsTasksOnCurrentThread()); |
74 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, | 78 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, |
75 "TaskQueueManager", this); | 79 "TaskQueueManager", this); |
76 selector_.SetTaskQueueSelectorObserver(this); | 80 selector_.SetTaskQueueSelectorObserver(this); |
77 | 81 |
78 from_main_thread_immediate_do_work_closure_ = | 82 delayed_do_work_closure_ = |
79 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), | 83 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true); |
80 base::TimeTicks(), true); | 84 immediate_do_work_closure_ = |
81 from_other_thread_immediate_do_work_closure_ = | 85 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false); |
82 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), | |
83 base::TimeTicks(), false); | |
84 | 86 |
85 // TODO(alexclarke): Change this to be a parameter that's passed in. | 87 // TODO(alexclarke): Change this to be a parameter that's passed in. |
86 RegisterTimeDomain(real_time_domain_.get()); | 88 RegisterTimeDomain(real_time_domain_.get()); |
87 | 89 |
88 delegate_->AddNestingObserver(this); | 90 delegate_->AddNestingObserver(this); |
89 } | 91 } |
90 | 92 |
91 TaskQueueManager::~TaskQueueManager() { | 93 TaskQueueManager::~TaskQueueManager() { |
92 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, | 94 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, |
93 "TaskQueueManager", this); | 95 "TaskQueueManager", this); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 DCHECK(main_thread_checker_.CalledOnValidThread()); | 140 DCHECK(main_thread_checker_.CalledOnValidThread()); |
139 if (observer_) | 141 if (observer_) |
140 observer_->OnUnregisterTaskQueue(task_queue); | 142 observer_->OnUnregisterTaskQueue(task_queue); |
141 | 143 |
142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being | 144 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being |
143 // freed while any of our structures hold hold a raw pointer to it. | 145 // freed while any of our structures hold hold a raw pointer to it. |
144 queues_to_delete_.insert(task_queue); | 146 queues_to_delete_.insert(task_queue); |
145 queues_.erase(task_queue); | 147 queues_.erase(task_queue); |
146 | 148 |
147 selector_.RemoveQueue(task_queue.get()); | 149 selector_.RemoveQueue(task_queue.get()); |
150 | |
151 { | |
152 SpinLock::Guard guard(do_work_pending_lock_); | |
153 has_incomming_immediate_work_.erase(task_queue.get()); | |
154 } | |
148 } | 155 } |
149 | 156 |
150 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) { | 157 void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) { |
151 TRACE_EVENT0(disabled_by_default_tracing_category_, | |
152 "TaskQueueManager::UpdateWorkQueues"); | |
153 | |
154 for (TimeDomain* time_domain : time_domains_) { | 158 for (TimeDomain* time_domain : time_domains_) { |
155 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get() | 159 if (time_domain == real_time_domain_.get()) { |
156 ? lazy_now | 160 time_domain->WakeupReadyDelayedQueues(lazy_now); |
157 : time_domain->CreateLazyNow(); | 161 continue; |
158 time_domain->UpdateWorkQueues(lazy_now_in_domain); | 162 } |
163 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow(); | |
164 time_domain->WakeupReadyDelayedQueues(&time_domain_lazy_now); | |
159 } | 165 } |
160 } | 166 } |
161 | 167 |
162 void TaskQueueManager::OnBeginNestedMessageLoop() { | 168 void TaskQueueManager::OnBeginNestedMessageLoop() { |
163 // We just entered a nested message loop, make sure there's a DoWork posted or | 169 // We just entered a nested message loop, make sure there's a DoWork posted or |
164 // the system will grind to a halt. | 170 // the system will grind to a halt. |
165 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); | 171 SpinLock::Guard guard(do_work_pending_lock_); |
Sami
2016/12/07 16:13:42
Seems risky holding to this during the PostTask --
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
172 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); | |
173 immediate_do_work_posted_count_++; | |
174 is_nested_ = true; | |
175 } | |
176 | |
177 void TaskQueueManager::OnQueueHasImmediateWork(internal::TaskQueueImpl* queue, | |
178 bool ensure_do_work_posted) { | |
179 SpinLock::Guard guard(do_work_pending_lock_); | |
180 has_incomming_immediate_work_.insert(queue); | |
181 if (ensure_do_work_posted) | |
182 MaybeScheduleImmediateWorkLocked(FROM_HERE); | |
183 } | |
184 | |
185 void TaskQueueManager::NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked() { | |
186 for (internal::TaskQueueImpl* queue : has_incomming_immediate_work_) { | |
187 queue->ReloadImmediateWorkQueueIfEmpty(); | |
188 } | |
189 has_incomming_immediate_work_.clear(); | |
166 } | 190 } |
167 | 191 |
168 void TaskQueueManager::MaybeScheduleImmediateWork( | 192 void TaskQueueManager::MaybeScheduleImmediateWork( |
169 const tracked_objects::Location& from_here) { | 193 const tracked_objects::Location& from_here) { |
170 bool on_main_thread = delegate_->BelongsToCurrentThread(); | 194 SpinLock::Guard guard(do_work_pending_lock_); |
171 // De-duplicate DoWork posts. | 195 MaybeScheduleImmediateWorkLocked(from_here); |
172 if (on_main_thread) { | 196 } |
173 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { | 197 |
174 return; | 198 void TaskQueueManager::MaybeScheduleImmediateWorkLocked( |
175 } | 199 const tracked_objects::Location& from_here) { |
176 delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_); | 200 // Unlwss we're ensted, try to avoid posting redundant DoWorks. |
Sami
2016/12/07 16:13:42
typo: Unless we're nested
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
177 } else { | 201 if (!is_nested_ && |
178 { | 202 (do_work_running_count_ == 1 || immediate_do_work_posted_count_ > 0)) { |
179 base::AutoLock lock(other_thread_lock_); | 203 return; |
180 if (other_thread_pending_wakeup_) | |
181 return; | |
182 other_thread_pending_wakeup_ = true; | |
183 } | |
184 delegate_->PostTask(from_here, | |
185 from_other_thread_immediate_do_work_closure_); | |
186 } | 204 } |
205 | |
206 delegate_->PostTask(from_here, immediate_do_work_closure_); | |
Sami
2016/12/07 16:13:42
Ditto about the spinlock and the PostTask.
alex clarke (OOO till 29th)
2016/12/08 17:40:28
Done.
| |
207 immediate_do_work_posted_count_++; | |
187 } | 208 } |
188 | 209 |
189 void TaskQueueManager::MaybeScheduleDelayedWork( | 210 void TaskQueueManager::MaybeScheduleDelayedWork( |
190 const tracked_objects::Location& from_here, | 211 const tracked_objects::Location& from_here, |
191 base::TimeTicks now, | 212 base::TimeTicks now, |
192 base::TimeDelta delay) { | 213 base::TimeDelta delay) { |
193 DCHECK(main_thread_checker_.CalledOnValidThread()); | 214 DCHECK(main_thread_checker_.CalledOnValidThread()); |
215 { | |
216 SpinLock::Guard guard(do_work_pending_lock_); | |
217 | |
218 // If there's a pending immediate DoWork then we rely on the logic in DoWork | |
219 // to post a continuation as needed. | |
220 if (immediate_do_work_posted_count_ > 0) | |
221 return; | |
222 | |
223 // If a non-nested DoWork is running we can also rely on the logic in DoWork | |
224 // to post a continuation as needed. | |
225 if (do_work_running_count_ == 1 && !is_nested_) | |
226 return; | |
227 } | |
228 MaybeScheduleDelayedWorkInternal(from_here, now, delay); | |
229 } | |
230 | |
231 void TaskQueueManager::MaybeScheduleDelayedWorkInternal( | |
232 const tracked_objects::Location& from_here, | |
233 base::TimeTicks now, | |
234 base::TimeDelta delay) { | |
194 DCHECK_GE(delay, base::TimeDelta()); | 235 DCHECK_GE(delay, base::TimeDelta()); |
195 | |
196 // If there's a pending immediate DoWork then we rely on | |
197 // TryAdvanceTimeDomains getting the TimeDomain to call | |
198 // MaybeScheduleDelayedWork again when the immediate DoWork is complete. | |
199 if (main_thread_pending_wakeups_.find(base::TimeTicks()) != | |
200 main_thread_pending_wakeups_.end()) { | |
201 return; | |
202 } | |
203 // De-duplicate DoWork posts. | 236 // De-duplicate DoWork posts. |
204 base::TimeTicks run_time = now + delay; | 237 base::TimeTicks run_time = now + delay; |
205 if (!main_thread_pending_wakeups_.empty() && | 238 if (next_delayed_do_work_ <= run_time && !next_delayed_do_work_.is_null()) |
206 *main_thread_pending_wakeups_.begin() <= run_time) { | |
207 return; | 239 return; |
208 } | 240 |
209 main_thread_pending_wakeups_.insert(run_time); | 241 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); |
242 next_delayed_do_work_ = run_time; | |
210 delegate_->PostDelayedTask( | 243 delegate_->PostDelayedTask( |
211 from_here, base::Bind(&TaskQueueManager::DoWork, | 244 from_here, cancelable_delayed_do_work_closure_.callback(), delay); |
212 weak_factory_.GetWeakPtr(), run_time, true), | |
213 delay); | |
214 } | 245 } |
215 | 246 |
216 void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { | 247 void TaskQueueManager::DoWork(bool delayed) { |
217 DCHECK(main_thread_checker_.CalledOnValidThread()); | 248 DCHECK(main_thread_checker_.CalledOnValidThread()); |
218 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", | 249 TRACE_EVENT1("tracing_category_", "TaskQueueManager::DoWork", "delayed", |
219 "from_main_thread", from_main_thread); | 250 delayed); |
251 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); | |
220 | 252 |
221 if (from_main_thread) { | 253 bool is_nested = delegate_->IsNested(); |
222 main_thread_pending_wakeups_.erase(run_time); | 254 if (!is_nested) |
223 } else { | |
224 base::AutoLock lock(other_thread_lock_); | |
225 other_thread_pending_wakeup_ = false; | |
226 } | |
227 | |
228 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. | |
229 main_thread_pending_wakeups_.insert(base::TimeTicks()); | |
230 | |
231 if (!delegate_->IsNested()) | |
232 queues_to_delete_.clear(); | 255 queues_to_delete_.clear(); |
233 | 256 |
234 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); | 257 for (int i = 0; i < work_batch_size_; i++) { |
235 UpdateWorkQueues(lazy_now); | 258 { |
259 SpinLock::Guard guard(do_work_pending_lock_); | |
236 | 260 |
237 for (int i = 0; i < work_batch_size_; i++) { | 261 is_nested_ = is_nested; |
238 internal::WorkQueue* work_queue; | 262 DCHECK_EQ(is_nested_, delegate_->IsNested()); |
263 | |
264 if (i == 0) { | |
265 do_work_running_count_++; | |
266 | |
267 if (!delayed) { | |
268 immediate_do_work_posted_count_--; | |
269 DCHECK_GE(immediate_do_work_posted_count_, 0); | |
270 } | |
271 } | |
272 | |
273 NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked(); | |
274 } | |
275 | |
276 UpdateWorkQueues(&lazy_now); | |
277 | |
278 internal::WorkQueue* work_queue = nullptr; | |
239 if (!SelectWorkQueueToService(&work_queue)) | 279 if (!SelectWorkQueueToService(&work_queue)) |
240 break; | 280 break; |
241 | 281 |
242 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { | 282 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) { |
243 case ProcessTaskResult::DEFERRED: | 283 case ProcessTaskResult::DEFERRED: |
244 // If a task was deferred, try again with another task. | 284 // If a task was deferred, try again with another task. |
245 continue; | 285 continue; |
246 case ProcessTaskResult::EXECUTED: | 286 case ProcessTaskResult::EXECUTED: |
247 break; | 287 break; |
248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: | 288 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: |
249 return; // The TaskQueueManager got deleted, we must bail out. | 289 return; // The TaskQueueManager got deleted, we must bail out. |
250 } | 290 } |
251 | 291 |
252 work_queue = nullptr; // The queue may have been unregistered. | 292 work_queue = nullptr; // The queue may have been unregistered. |
253 | 293 |
254 UpdateWorkQueues(lazy_now); | |
255 | |
256 // Only run a single task per batch in nested run loops so that we can | 294 // Only run a single task per batch in nested run loops so that we can |
257 // properly exit the nested loop when someone calls RunLoop::Quit(). | 295 // properly exit the nested loop when someone calls RunLoop::Quit(). |
258 if (delegate_->IsNested()) | 296 if (is_nested) |
259 break; | 297 break; |
260 } | 298 } |
261 | 299 |
262 main_thread_pending_wakeups_.erase(base::TimeTicks()); | |
263 | |
264 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 300 // TODO(alexclarke): Consider refactoring the above loop to terminate only |
265 // when there's no more work left to be done, rather than posting a | 301 // when there's no more work left to be done, rather than posting a |
266 // continuation task. | 302 // continuation task. |
267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains()) | 303 if (delayed) |
268 MaybeScheduleImmediateWork(FROM_HERE); | 304 next_delayed_do_work_ = base::TimeTicks(); |
305 | |
306 // If we know we're about to post an immediate do work, then there's no point | |
307 // calling UpdateWorkQueues since that'll get done by the next DoWork. | |
308 bool work_queues_might_be_empty = selector_.EnabledWorkQueuesEmpty(); | |
309 if (work_queues_might_be_empty) | |
310 UpdateWorkQueues(&lazy_now); | |
311 | |
312 SpinLock::Guard guard(do_work_pending_lock_); | |
Sami
2016/12/07 16:13:42
Could you also delimit this scope explicitly? Feel
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
313 | |
314 // Likewise it's only worth calling | |
315 // NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked if it looks like we | |
316 // might have run out of immediate work to do. | |
317 if (work_queues_might_be_empty) | |
318 NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked(); | |
319 | |
320 base::Optional<base::TimeDelta> next_delay = DelayTillNextTask(&lazy_now); | |
321 DCHECK(work_queues_might_be_empty || | |
322 (next_delay && next_delay.value().is_zero())); | |
323 | |
324 do_work_running_count_--; | |
325 DCHECK_GE(do_work_running_count_, 0); | |
326 | |
327 is_nested_ = is_nested; | |
328 DCHECK_EQ(is_nested_, delegate_->IsNested()); | |
329 | |
330 PostDoWorkContinuation(next_delay, &lazy_now); | |
269 } | 331 } |
270 | 332 |
271 bool TaskQueueManager::TryAdvanceTimeDomains() { | 333 void TaskQueueManager::PostDoWorkContinuation( |
Sami
2016/12/07 16:13:42
...Locked()?
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
272 bool can_advance = false; | 334 base::Optional<base::TimeDelta> next_delay, |
335 LazyNow* lazy_now) { | |
336 // If there are no tasks left then we don't need to post a continuation. | |
337 if (!next_delay) | |
338 return; | |
339 | |
340 // If either an immediate DoWork or a delayed DoWork is pending then we don't | |
341 // need to post a continuation. | |
342 if (immediate_do_work_posted_count_ > 0 || | |
343 (!next_delayed_do_work_.is_null() && | |
344 next_delayed_do_work_ <= lazy_now->Now())) { | |
345 return; | |
346 } | |
347 | |
348 // Post a continuation task based on the delay till the next task. | |
349 if (next_delay.value().is_zero()) { | |
350 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); | |
Sami
2016/12/07 16:13:42
Ditto about calling into the delegate/selector/tim
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
351 immediate_do_work_posted_count_++; | |
352 } else { | |
353 MaybeScheduleDelayedWorkInternal(FROM_HERE, lazy_now->Now(), | |
354 next_delay.value()); | |
355 } | |
356 } | |
357 | |
358 base::Optional<base::TimeDelta> TaskQueueManager::DelayTillNextTask( | |
359 LazyNow* lazy_now) { | |
360 // If the selector has non-empty queues we trivially know there is immediate | |
361 // word to be done. | |
362 if (!selector_.EnabledWorkQueuesEmpty()) | |
363 return base::TimeDelta(); | |
364 | |
365 // Otherwise we need to find the shortest delay, if any. | |
366 base::Optional<base::TimeDelta> next_continuation; | |
273 for (TimeDomain* time_domain : time_domains_) { | 367 for (TimeDomain* time_domain : time_domains_) { |
274 can_advance |= time_domain->MaybeAdvanceTime(); | 368 base::Optional<base::TimeDelta> continuation = |
369 time_domain->DelayTillNextTask(lazy_now); | |
370 if (!continuation) | |
371 continue; | |
372 if (!next_continuation || next_continuation.value() < continuation.value()) | |
Sami
2016/12/07 16:13:42
Should '<' be '>' or am I missing something?
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Good catch, I added a test.
| |
373 next_continuation = continuation; | |
275 } | 374 } |
276 return can_advance; | 375 return next_continuation; |
277 } | 376 } |
278 | 377 |
279 bool TaskQueueManager::SelectWorkQueueToService( | 378 bool TaskQueueManager::SelectWorkQueueToService( |
Sami
2016/12/07 16:13:42
...Locked()?
alex clarke (OOO till 29th)
2016/12/08 17:38:48
This doesn't need to be locked?
| |
280 internal::WorkQueue** out_work_queue) { | 379 internal::WorkQueue** out_work_queue) { |
281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); | 380 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); |
282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( | 381 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( |
283 disabled_by_default_tracing_category_, "TaskQueueManager", this, | 382 disabled_by_default_tracing_category_, "TaskQueueManager", this, |
284 AsValueWithSelectorResult(should_run, *out_work_queue)); | 383 AsValueWithSelectorResult(should_run, *out_work_queue)); |
285 return should_run; | 384 return should_run; |
286 } | 385 } |
287 | 386 |
288 void TaskQueueManager::DidQueueTask( | 387 void TaskQueueManager::DidQueueTask( |
289 const internal::TaskQueueImpl::Task& pending_task) { | 388 const internal::TaskQueueImpl::Task& pending_task) { |
290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); | 389 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); |
291 } | 390 } |
292 | 391 |
293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( | 392 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( |
294 internal::WorkQueue* work_queue, | 393 internal::WorkQueue* work_queue, |
295 LazyNow* lazy_now) { | 394 LazyNow* lazy_now) { |
296 DCHECK(main_thread_checker_.CalledOnValidThread()); | 395 DCHECK(main_thread_checker_.CalledOnValidThread()); |
297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); | 396 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); |
298 internal::TaskQueueImpl::Task pending_task = | 397 internal::TaskQueueImpl::Task pending_task = |
299 work_queue->TakeTaskFromWorkQueue(); | 398 work_queue->TakeTaskFromWorkQueue(); |
300 | 399 |
301 // It's possible the task was canceled, if so bail out. | 400 // It's possible the task was canceled, if so bail out. |
302 if (pending_task.task.IsCancelled()) | 401 if (pending_task.task.IsCancelled()) |
303 return ProcessTaskResult::EXECUTED; | 402 return ProcessTaskResult::EXECUTED; |
304 | 403 |
305 internal::TaskQueueImpl* queue = work_queue->task_queue(); | 404 internal::TaskQueueImpl* queue = work_queue->task_queue(); |
306 if (queue->GetQuiescenceMonitored()) | 405 if (queue->GetQuiescenceMonitored()) |
307 task_was_run_on_quiescence_monitored_queue_ = true; | 406 task_was_run_on_quiescence_monitored_queue_ = true; |
308 | 407 |
309 if (!pending_task.nestable && delegate_->IsNested()) { | 408 DCHECK_EQ(is_nested_, delegate_->IsNested()); |
409 if (!pending_task.nestable && is_nested_) { | |
310 // Defer non-nestable work to the main task runner. NOTE these tasks can be | 410 // Defer non-nestable work to the main task runner. NOTE these tasks can be |
311 // arbitrarily delayed so the additional delay should not be a problem. | 411 // arbitrarily delayed so the additional delay should not be a problem. |
312 // TODO(skyostil): Figure out a way to not forget which task queue the | 412 // TODO(skyostil): Figure out a way to not forget which task queue the |
313 // task is associated with. See http://crbug.com/522843. | 413 // task is associated with. See http://crbug.com/522843. |
314 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once | 414 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once |
315 // TaskRunners have migrated to OnceClosure. | 415 // TaskRunners have migrated to OnceClosure. |
316 delegate_->PostNonNestableTask( | 416 delegate_->PostNonNestableTask( |
317 pending_task.posted_from, | 417 pending_task.posted_from, |
318 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); | 418 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); |
319 return ProcessTaskResult::DEFERRED; | 419 return ProcessTaskResult::DEFERRED; |
320 } | 420 } |
321 | 421 |
322 MaybeRecordTaskDelayHistograms(pending_task, queue); | 422 if (record_task_delay_histograms_) |
423 MaybeRecordTaskDelayHistograms(pending_task, queue); | |
323 | 424 |
324 double task_start_time = 0; | 425 double task_start_time = 0; |
325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", | 426 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", |
326 pending_task); | 427 pending_task); |
327 if (queue->GetShouldNotifyObservers()) { | 428 if (queue->GetShouldNotifyObservers()) { |
328 for (auto& observer : task_observers_) | 429 for (auto& observer : task_observers_) |
329 observer.WillProcessTask(pending_task); | 430 observer.WillProcessTask(pending_task); |
330 queue->NotifyWillProcessTask(pending_task); | 431 queue->NotifyWillProcessTask(pending_task); |
331 | 432 |
332 bool notify_time_observers = | 433 bool notify_time_observers = |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
463 if (should_run) { | 564 if (should_run) { |
464 state->SetString("selected_queue", | 565 state->SetString("selected_queue", |
465 selected_work_queue->task_queue()->GetName()); | 566 selected_work_queue->task_queue()->GetName()); |
466 state->SetString("work_queue_name", selected_work_queue->name()); | 567 state->SetString("work_queue_name", selected_work_queue->name()); |
467 } | 568 } |
468 | 569 |
469 state->BeginArray("time_domains"); | 570 state->BeginArray("time_domains"); |
470 for (auto* time_domain : time_domains_) | 571 for (auto* time_domain : time_domains_) |
471 time_domain->AsValueInto(state.get()); | 572 time_domain->AsValueInto(state.get()); |
472 state->EndArray(); | 573 state->EndArray(); |
574 | |
575 state->SetBoolean("is_nested", is_nested_); | |
Sami
2016/12/07 16:13:42
Looks like this should be inside the lock.
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
576 | |
577 SpinLock::Guard guard(do_work_pending_lock_); | |
Sami
2016/12/07 16:13:42
nit: explicit scope please.
alex clarke (OOO till 29th)
2016/12/08 17:38:48
Done.
| |
578 state->SetInteger("do_work_count", do_work_running_count_); | |
579 state->SetInteger("immediate_do_work_posted", | |
580 immediate_do_work_posted_count_); | |
473 return std::move(state); | 581 return std::move(state); |
474 } | 582 } |
475 | 583 |
476 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { | 584 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { |
477 DCHECK(main_thread_checker_.CalledOnValidThread()); | 585 DCHECK(main_thread_checker_.CalledOnValidThread()); |
478 // Only schedule DoWork if there's something to do. | 586 // Only schedule DoWork if there's something to do. |
479 if (queue->HasPendingImmediateWork()) | 587 if (queue->HasPendingImmediateWork()) |
480 MaybeScheduleImmediateWork(FROM_HERE); | 588 MaybeScheduleImmediateWork(FROM_HERE); |
481 } | 589 } |
482 | 590 |
483 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( | 591 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( |
484 internal::WorkQueue* work_queue) { | 592 internal::WorkQueue* work_queue) { |
485 DCHECK(main_thread_checker_.CalledOnValidThread()); | 593 DCHECK(main_thread_checker_.CalledOnValidThread()); |
486 DCHECK(!work_queue->Empty()); | 594 DCHECK(!work_queue->Empty()); |
487 if (observer_) { | 595 if (observer_) { |
488 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), | 596 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), |
489 *work_queue->GetFrontTask()); | 597 *work_queue->GetFrontTask()); |
490 } | 598 } |
491 } | 599 } |
492 | 600 |
493 bool TaskQueueManager::HasImmediateWorkForTesting() const { | 601 bool TaskQueueManager::HasImmediateWorkForTesting() const { |
494 return !selector_.EnabledWorkQueuesEmpty(); | 602 return !selector_.EnabledWorkQueuesEmpty(); |
495 } | 603 } |
496 | 604 |
605 void TaskQueueManager::SetRecordTaskDelayHistograms( | |
606 bool record_task_delay_histograms) { | |
607 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
608 record_task_delay_histograms_ = record_task_delay_histograms; | |
609 } | |
610 | |
497 } // namespace scheduler | 611 } // namespace scheduler |
498 } // namespace blink | 612 } // namespace blink |
OLD | NEW |