Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc

Issue 2546423002: [Try # 3] Scheduler refactoring to virtually eliminate redundant DoWorks (Closed)
Patch Set: Rebased Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698