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

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

Issue 2572893002: [Reland] Dont post delayed DoWork for disabled queues. (Closed)
Patch Set: Keep track of which TimeDomain the delayed do works are associated with. Created 3 years, 10 months 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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 any_thread().immediate_do_work_posted_count++; 223 any_thread().immediate_do_work_posted_count++;
224 } 224 }
225 225
226 TRACE_EVENT0(disabled_by_default_tracing_category_, 226 TRACE_EVENT0(disabled_by_default_tracing_category_,
227 "TaskQueueManager::MaybeScheduleImmediateWorkLocked::PostTask"); 227 "TaskQueueManager::MaybeScheduleImmediateWorkLocked::PostTask");
228 delegate_->PostTask(from_here, immediate_do_work_closure_); 228 delegate_->PostTask(from_here, immediate_do_work_closure_);
229 } 229 }
230 230
231 void TaskQueueManager::MaybeScheduleDelayedWork( 231 void TaskQueueManager::MaybeScheduleDelayedWork(
232 const tracked_objects::Location& from_here, 232 const tracked_objects::Location& from_here,
233 base::TimeTicks now, 233 TimeDomain* requesting_time_domain,
234 base::TimeDelta delay) { 234 LazyNow* lazy_now,
235 base::TimeTicks run_time) {
235 DCHECK(main_thread_checker_.CalledOnValidThread()); 236 DCHECK(main_thread_checker_.CalledOnValidThread());
Sami 2017/02/01 07:30:05 DCHECK(!next_delayed_do_work_ || next_delayed_do_w
alex clarke (OOO till 29th) 2017/02/01 14:50:11 Done.
236 DCHECK_GE(delay, base::TimeDelta());
237 { 237 {
238 base::AutoLock lock(any_thread_lock_); 238 base::AutoLock lock(any_thread_lock_);
239 239
240 // Unless we're nested, don't post a delayed DoWork if there's an immediate 240 // Unless we're nested, don't post a delayed DoWork if there's an immediate
241 // DoWork in flight or we're inside a DoWork. We can rely on DoWork posting 241 // DoWork in flight or we're inside a DoWork. We can rely on DoWork posting
242 // a delayed continuation as needed. 242 // a delayed continuation as needed.
243 if (!any_thread().is_nested && 243 if (!any_thread().is_nested &&
244 (any_thread().immediate_do_work_posted_count > 0 || 244 (any_thread().immediate_do_work_posted_count > 0 ||
245 any_thread().do_work_running_count == 1)) { 245 any_thread().do_work_running_count == 1)) {
246 return; 246 return;
247 } 247 }
248 } 248 }
249 249
250 // De-duplicate DoWork posts. 250 // De-duplicate DoWork posts.
251 base::TimeTicks run_time = now + delay; 251 if (next_delayed_do_work_ && next_delayed_do_work_.run_time() <= run_time)
252 if (next_scheduled_delayed_do_work_time_ <= run_time &&
253 !next_scheduled_delayed_do_work_time_.is_null())
254 return; 252 return;
255 253
254 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
255
256 base::TimeDelta delay =
257 std::max(base::TimeDelta(), run_time - lazy_now->Now());
258
256 TRACE_EVENT1(disabled_by_default_tracing_category_, 259 TRACE_EVENT1(disabled_by_default_tracing_category_,
257 "TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask", 260 "TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask",
258 "delay_ms", delay.InMillisecondsF()); 261 "delay_ms", delay.InMillisecondsF());
259 262
260 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); 263 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
261 next_scheduled_delayed_do_work_time_ = run_time; 264 next_delayed_do_work_ = NextDelayedDoWork(run_time, requesting_time_domain);
262 delegate_->PostDelayedTask( 265 delegate_->PostDelayedTask(
263 from_here, cancelable_delayed_do_work_closure_.callback(), delay); 266 from_here, cancelable_delayed_do_work_closure_.callback(), delay);
264 } 267 }
265 268
269 void TaskQueueManager::CancelDelayedWork(TimeDomain* requesting_time_domain,
270 base::TimeTicks run_time) {
271 DCHECK(main_thread_checker_.CalledOnValidThread());
272 if (next_delayed_do_work_.run_time() != run_time)
273 return;
274
275 DCHECK_EQ(next_delayed_do_work_.time_domain(), requesting_time_domain);
276 cancelable_delayed_do_work_closure_.Cancel();
277 next_delayed_do_work_.Clear();
278 }
279
266 void TaskQueueManager::DoWork(bool delayed) { 280 void TaskQueueManager::DoWork(bool delayed) {
267 DCHECK(main_thread_checker_.CalledOnValidThread()); 281 DCHECK(main_thread_checker_.CalledOnValidThread());
268 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed", 282 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed",
269 delayed); 283 delayed);
270 284
271 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 285 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
272 bool is_nested = delegate_->IsNested(); 286 bool is_nested = delegate_->IsNested();
273 if (!is_nested) 287 if (!is_nested)
274 queues_to_delete_.clear(); 288 queues_to_delete_.clear();
275 289
276 // This must be done before running any tasks because they could invoke a 290 // This must be done before running any tasks because they could invoke a
277 // nested message loop and we risk having a stale 291 // nested message loop and we risk having a stale
278 // |next_scheduled_delayed_do_work_time_|. 292 // |next_delayed_do_work_|.
Sami 2017/02/01 07:30:04 nit: rewrap
alex clarke (OOO till 29th) 2017/02/01 14:50:11 Done.
279 if (delayed) 293 if (delayed)
280 next_scheduled_delayed_do_work_time_ = base::TimeTicks(); 294 next_delayed_do_work_.Clear();
295 ;
Sami 2017/02/01 07:30:04 Extra ';'?
alex clarke (OOO till 29th) 2017/02/01 14:50:11 Done.
281 296
282 for (int i = 0; i < work_batch_size_; i++) { 297 for (int i = 0; i < work_batch_size_; i++) {
283 IncomingImmediateWorkMap queues_to_reload; 298 IncomingImmediateWorkMap queues_to_reload;
284 299
285 { 300 {
286 base::AutoLock lock(any_thread_lock_); 301 base::AutoLock lock(any_thread_lock_);
287 if (i == 0) { 302 if (i == 0) {
288 any_thread().do_work_running_count++; 303 any_thread().do_work_running_count++;
289 304
290 if (!delayed) { 305 if (!delayed) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 if (is_nested) 347 if (is_nested)
333 break; 348 break;
334 } 349 }
335 350
336 // TODO(alexclarke): Consider refactoring the above loop to terminate only 351 // TODO(alexclarke): Consider refactoring the above loop to terminate only
337 // when there's no more work left to be done, rather than posting a 352 // when there's no more work left to be done, rather than posting a
338 // continuation task. 353 // continuation task.
339 354
340 { 355 {
341 MoveableAutoLock lock(any_thread_lock_); 356 MoveableAutoLock lock(any_thread_lock_);
342 base::Optional<base::TimeDelta> next_delay = 357 base::Optional<NextTaskDelay> next_delay =
343 ComputeDelayTillNextTaskLocked(&lazy_now); 358 ComputeDelayTillNextTaskLocked(&lazy_now);
344 359
345 any_thread().do_work_running_count--; 360 any_thread().do_work_running_count--;
346 DCHECK_GE(any_thread().do_work_running_count, 0); 361 DCHECK_GE(any_thread().do_work_running_count, 0);
347 362
348 any_thread().is_nested = is_nested; 363 any_thread().is_nested = is_nested;
349 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); 364 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested());
350 365
351 PostDoWorkContinuationLocked(next_delay, &lazy_now, std::move(lock)); 366 PostDoWorkContinuationLocked(next_delay, &lazy_now, std::move(lock));
352 } 367 }
353 } 368 }
354 369
355 void TaskQueueManager::PostDoWorkContinuationLocked( 370 void TaskQueueManager::PostDoWorkContinuationLocked(
356 base::Optional<base::TimeDelta> next_delay, 371 base::Optional<NextTaskDelay> next_delay,
357 LazyNow* lazy_now, 372 LazyNow* lazy_now,
358 MoveableAutoLock&& lock) { 373 MoveableAutoLock&& lock) {
359 DCHECK(main_thread_checker_.CalledOnValidThread()); 374 DCHECK(main_thread_checker_.CalledOnValidThread());
360 base::TimeDelta delay; 375 base::TimeDelta delay;
361 376
362 { 377 {
363 MoveableAutoLock auto_lock(std::move(lock)); 378 MoveableAutoLock auto_lock(std::move(lock));
364 379
365 // If there are no tasks left then we don't need to post a continuation. 380 // If there are no tasks left then we don't need to post a continuation.
366 if (!next_delay) { 381 if (!next_delay) {
367 // If there's a pending delayed DoWork, cancel it because it's not needed. 382 // If there's a pending delayed DoWork, cancel it because it's not needed.
368 if (!next_scheduled_delayed_do_work_time_.is_null()) { 383 if (next_delayed_do_work_) {
369 next_scheduled_delayed_do_work_time_ = base::TimeTicks(); 384 next_delayed_do_work_.Clear();
370 cancelable_delayed_do_work_closure_.Cancel(); 385 cancelable_delayed_do_work_closure_.Cancel();
371 } 386 }
372 return; 387 return;
373 } 388 }
374 389
375 // If an immediate DoWork is posted, we don't need to post a continuation. 390 // If an immediate DoWork is posted, we don't need to post a continuation.
376 if (any_thread().immediate_do_work_posted_count > 0) 391 if (any_thread().immediate_do_work_posted_count > 0)
377 return; 392 return;
378 393
379 delay = next_delay.value(); 394 delay = next_delay->delay();
380 395
381 // This isn't supposed to happen, but in case it does convert to 396 // This isn't supposed to happen, but in case it does convert to
382 // non-delayed. 397 // non-delayed.
383 if (delay < base::TimeDelta()) 398 if (delay < base::TimeDelta())
384 delay = base::TimeDelta(); 399 delay = base::TimeDelta();
385 400
386 if (delay.is_zero()) { 401 if (delay.is_zero()) {
387 // If a delayed DoWork is pending then we don't need to post a 402 // If a delayed DoWork is pending then we don't need to post a
388 // continuation because it should run immediately. 403 // continuation because it should run immediately.
389 if (!next_scheduled_delayed_do_work_time_.is_null() && 404 if (next_delayed_do_work_ &&
390 next_scheduled_delayed_do_work_time_ <= lazy_now->Now()) { 405 next_delayed_do_work_.run_time() <= lazy_now->Now()) {
391 return; 406 return;
392 } 407 }
393 408
394 any_thread().immediate_do_work_posted_count++; 409 any_thread().immediate_do_work_posted_count++;
395 } else {
396 base::TimeTicks run_time = lazy_now->Now() + delay;
397 if (next_scheduled_delayed_do_work_time_ == run_time)
398 return;
399
400 next_scheduled_delayed_do_work_time_ = run_time;
401 } 410 }
402 } 411 }
403 412
404 // We avoid holding |any_thread_lock_| while posting the task. 413 // We avoid holding |any_thread_lock_| while posting the task.
405 if (delay.is_zero()) { 414 if (delay.is_zero()) {
406 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); 415 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_);
407 } else { 416 } else {
417 base::TimeTicks run_time = lazy_now->Now() + delay;
418 if (next_delayed_do_work_.run_time() == run_time)
419 return;
420
421 next_delayed_do_work_ =
422 NextDelayedDoWork(run_time, next_delay->time_domain());
408 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); 423 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
409 delegate_->PostDelayedTask( 424 delegate_->PostDelayedTask(
410 FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay); 425 FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay);
411 } 426 }
412 } 427 }
413 428
414 base::Optional<base::TimeDelta> 429 base::Optional<TaskQueueManager::NextTaskDelay>
415 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) { 430 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) {
416 DCHECK(main_thread_checker_.CalledOnValidThread()); 431 DCHECK(main_thread_checker_.CalledOnValidThread());
417 432
418 // Unfortunately because |any_thread_lock_| is held it's not safe to call 433 // Unfortunately because |any_thread_lock_| is held it's not safe to call
419 // ReloadEmptyWorkQueues here (possible lock order inversion), however this 434 // ReloadEmptyWorkQueues here (possible lock order inversion), however this
420 // check is equavalent to calling ReloadEmptyWorkQueues first. 435 // check is equavalent to calling ReloadEmptyWorkQueues first.
421 for (const auto& pair : any_thread().has_incoming_immediate_work) { 436 for (const auto& pair : any_thread().has_incoming_immediate_work) {
422 if (pair.first->CouldTaskRun(pair.second)) 437 if (pair.first->CouldTaskRun(pair.second))
423 return base::TimeDelta(); 438 return NextTaskDelay();
424 } 439 }
425 440
426 // If the selector has non-empty queues we trivially know there is immediate 441 // If the selector has non-empty queues we trivially know there is immediate
427 // work to be done. 442 // work to be done.
428 if (!selector_.EnabledWorkQueuesEmpty()) 443 if (!selector_.EnabledWorkQueuesEmpty())
429 return base::TimeDelta(); 444 return NextTaskDelay();
430 445
431 // Otherwise we need to find the shortest delay, if any. NB we don't need to 446 // Otherwise we need to find the shortest delay, if any. NB we don't need to
432 // call WakeupReadyDelayedQueues because it's assumed DelayTillNextTask will 447 // call WakeupReadyDelayedQueues because it's assumed DelayTillNextTask will
433 // return base::TimeDelta>() if the delayed task is due to run now. 448 // return base::TimeDelta>() if the delayed task is due to run now.
434 base::Optional<base::TimeDelta> next_continuation; 449 base::Optional<NextTaskDelay> delay_till_next_task;
435 for (TimeDomain* time_domain : time_domains_) { 450 for (TimeDomain* time_domain : time_domains_) {
436 base::Optional<base::TimeDelta> continuation = 451 base::Optional<base::TimeDelta> delay =
437 time_domain->DelayTillNextTask(lazy_now); 452 time_domain->DelayTillNextTask(lazy_now);
438 if (!continuation) 453 if (!delay)
439 continue; 454 continue;
440 if (!next_continuation || next_continuation.value() > continuation.value()) 455
441 next_continuation = continuation; 456 NextTaskDelay task_delay = (delay.value() == base::TimeDelta())
457 ? NextTaskDelay()
458 : NextTaskDelay(delay.value(), time_domain);
459
460 if (!delay_till_next_task || task_delay < delay_till_next_task.value())
461 delay_till_next_task = task_delay;
442 } 462 }
443 return next_continuation; 463 return delay_till_next_task;
444 } 464 }
445 465
446 bool TaskQueueManager::SelectWorkQueueToService( 466 bool TaskQueueManager::SelectWorkQueueToService(
447 internal::WorkQueue** out_work_queue) { 467 internal::WorkQueue** out_work_queue) {
448 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); 468 bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
449 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 469 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
450 disabled_by_default_tracing_category_, "TaskQueueManager", this, 470 disabled_by_default_tracing_category_, "TaskQueueManager", this,
451 AsValueWithSelectorResult(should_run, *out_work_queue)); 471 AsValueWithSelectorResult(should_run, *out_work_queue));
452 return should_run; 472 return should_run;
453 } 473 }
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { 711 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) {
692 TimeDomain* time_domain = queue->GetTimeDomain(); 712 TimeDomain* time_domain = queue->GetTimeDomain();
693 if (time_domain_now.find(time_domain) == time_domain_now.end()) 713 if (time_domain_now.find(time_domain) == time_domain_now.end())
694 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); 714 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now()));
695 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); 715 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]);
696 } 716 }
697 } 717 }
698 718
699 } // namespace scheduler 719 } // namespace scheduler
700 } // namespace blink 720 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698