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

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: Fix compile 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 TimeDomain* requesting_time_domain,
233 base::TimeTicks now, 234 base::TimeTicks now,
234 base::TimeDelta delay) { 235 base::TimeTicks run_time) {
235 DCHECK(main_thread_checker_.CalledOnValidThread()); 236 DCHECK(main_thread_checker_.CalledOnValidThread());
236 DCHECK_GE(delay, base::TimeDelta()); 237 // Make sure we don't cancel another TimeDomain's wakeup.
238 DCHECK(!next_delayed_do_work_ ||
239 next_delayed_do_work_.time_domain() == requesting_time_domain);
237 { 240 {
238 base::AutoLock lock(any_thread_lock_); 241 base::AutoLock lock(any_thread_lock_);
239 242
240 // Unless we're nested, don't post a delayed DoWork if there's an immediate 243 // 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 244 // DoWork in flight or we're inside a DoWork. We can rely on DoWork posting
242 // a delayed continuation as needed. 245 // a delayed continuation as needed.
243 if (!any_thread().is_nested && 246 if (!any_thread().is_nested &&
244 (any_thread().immediate_do_work_posted_count > 0 || 247 (any_thread().immediate_do_work_posted_count > 0 ||
245 any_thread().do_work_running_count == 1)) { 248 any_thread().do_work_running_count == 1)) {
246 return; 249 return;
247 } 250 }
248 } 251 }
249 252
250 // De-duplicate DoWork posts. 253 // If there's a delayed DoWork scheduled to run sooner, we don't need to do
251 base::TimeTicks run_time = now + delay; 254 // anything because DoWork will post a delayed continuation as needed.
252 if (next_scheduled_delayed_do_work_time_ <= run_time && 255 if (next_delayed_do_work_ && next_delayed_do_work_.run_time() <= run_time)
253 !next_scheduled_delayed_do_work_time_.is_null())
254 return; 256 return;
255 257
258 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
259
260 base::TimeDelta delay = std::max(base::TimeDelta(), run_time - now);
256 TRACE_EVENT1(disabled_by_default_tracing_category_, 261 TRACE_EVENT1(disabled_by_default_tracing_category_,
257 "TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask", 262 "TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask",
258 "delay_ms", delay.InMillisecondsF()); 263 "delay_ms", delay.InMillisecondsF());
259 264
260 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); 265 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
261 next_scheduled_delayed_do_work_time_ = run_time; 266 next_delayed_do_work_ = NextDelayedDoWork(run_time, requesting_time_domain);
262 delegate_->PostDelayedTask( 267 delegate_->PostDelayedTask(
263 from_here, cancelable_delayed_do_work_closure_.callback(), delay); 268 from_here, cancelable_delayed_do_work_closure_.callback(), delay);
264 } 269 }
265 270
271 void TaskQueueManager::CancelDelayedWork(TimeDomain* requesting_time_domain,
272 base::TimeTicks run_time) {
273 DCHECK(main_thread_checker_.CalledOnValidThread());
274 if (next_delayed_do_work_.run_time() != run_time)
275 return;
276
277 DCHECK_EQ(next_delayed_do_work_.time_domain(), requesting_time_domain);
278 cancelable_delayed_do_work_closure_.Cancel();
279 next_delayed_do_work_.Clear();
280 }
281
266 void TaskQueueManager::DoWork(bool delayed) { 282 void TaskQueueManager::DoWork(bool delayed) {
267 DCHECK(main_thread_checker_.CalledOnValidThread()); 283 DCHECK(main_thread_checker_.CalledOnValidThread());
268 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed", 284 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed",
269 delayed); 285 delayed);
270 286
271 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); 287 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
272 bool is_nested = delegate_->IsNested(); 288 bool is_nested = delegate_->IsNested();
273 if (!is_nested) 289 if (!is_nested)
274 queues_to_delete_.clear(); 290 queues_to_delete_.clear();
275 291
276 // This must be done before running any tasks because they could invoke a 292 // This must be done before running any tasks because they could invoke a
277 // nested message loop and we risk having a stale 293 // nested message loop and we risk having a stale |next_delayed_do_work_|.
278 // |next_scheduled_delayed_do_work_time_|.
279 if (delayed) 294 if (delayed)
280 next_scheduled_delayed_do_work_time_ = base::TimeTicks(); 295 next_delayed_do_work_.Clear();
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;
361 375
362 { 376 {
363 MoveableAutoLock auto_lock(std::move(lock)); 377 MoveableAutoLock auto_lock(std::move(lock));
364 378
365 // If there are no tasks left then we don't need to post a continuation. 379 // If there are no tasks left then we don't need to post a continuation.
366 if (!next_delay) { 380 if (!next_delay) {
367 // If there's a pending delayed DoWork, cancel it because it's not needed. 381 // If there's a pending delayed DoWork, cancel it because it's not needed.
368 if (!next_scheduled_delayed_do_work_time_.is_null()) { 382 if (next_delayed_do_work_) {
369 next_scheduled_delayed_do_work_time_ = base::TimeTicks(); 383 next_delayed_do_work_.Clear();
370 cancelable_delayed_do_work_closure_.Cancel(); 384 cancelable_delayed_do_work_closure_.Cancel();
371 } 385 }
372 return; 386 return;
373 } 387 }
374 388
375 // If an immediate DoWork is posted, we don't need to post a continuation. 389 // If an immediate DoWork is posted, we don't need to post a continuation.
376 if (any_thread().immediate_do_work_posted_count > 0) 390 if (any_thread().immediate_do_work_posted_count > 0)
377 return; 391 return;
378 392
379 delay = next_delay.value(); 393 if (next_delay->delay() <= base::TimeDelta()) {
380
381 // This isn't supposed to happen, but in case it does convert to
382 // non-delayed.
383 if (delay < base::TimeDelta())
384 delay = base::TimeDelta();
385
386 if (delay.is_zero()) {
387 // If a delayed DoWork is pending then we don't need to post a 394 // If a delayed DoWork is pending then we don't need to post a
388 // continuation because it should run immediately. 395 // continuation because it should run immediately.
389 if (!next_scheduled_delayed_do_work_time_.is_null() && 396 if (next_delayed_do_work_ &&
390 next_scheduled_delayed_do_work_time_ <= lazy_now->Now()) { 397 next_delayed_do_work_.run_time() <= lazy_now->Now()) {
391 return; 398 return;
392 } 399 }
393 400
394 any_thread().immediate_do_work_posted_count++; 401 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 } 402 }
402 } 403 }
403 404
404 // We avoid holding |any_thread_lock_| while posting the task. 405 // We avoid holding |any_thread_lock_| while posting the task.
405 if (delay.is_zero()) { 406 if (next_delay->delay() <= base::TimeDelta()) {
406 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); 407 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_);
407 } else { 408 } else {
409 base::TimeTicks run_time = lazy_now->Now() + next_delay->delay();
410
411 if (next_delayed_do_work_.run_time() == run_time)
412 return;
413
414 next_delayed_do_work_ =
415 NextDelayedDoWork(run_time, next_delay->time_domain());
408 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); 416 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
409 delegate_->PostDelayedTask( 417 delegate_->PostDelayedTask(FROM_HERE,
410 FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay); 418 cancelable_delayed_do_work_closure_.callback(),
419 next_delay->delay());
411 } 420 }
412 } 421 }
413 422
414 base::Optional<base::TimeDelta> 423 base::Optional<TaskQueueManager::NextTaskDelay>
415 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) { 424 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) {
416 DCHECK(main_thread_checker_.CalledOnValidThread()); 425 DCHECK(main_thread_checker_.CalledOnValidThread());
417 426
418 // Unfortunately because |any_thread_lock_| is held it's not safe to call 427 // Unfortunately because |any_thread_lock_| is held it's not safe to call
419 // ReloadEmptyWorkQueues here (possible lock order inversion), however this 428 // ReloadEmptyWorkQueues here (possible lock order inversion), however this
420 // check is equavalent to calling ReloadEmptyWorkQueues first. 429 // check is equavalent to calling ReloadEmptyWorkQueues first.
421 for (const auto& pair : any_thread().has_incoming_immediate_work) { 430 for (const auto& pair : any_thread().has_incoming_immediate_work) {
422 if (pair.first->CouldTaskRun(pair.second)) 431 if (pair.first->CouldTaskRun(pair.second))
423 return base::TimeDelta(); 432 return NextTaskDelay();
424 } 433 }
425 434
426 // If the selector has non-empty queues we trivially know there is immediate 435 // If the selector has non-empty queues we trivially know there is immediate
427 // work to be done. 436 // work to be done.
428 if (!selector_.EnabledWorkQueuesEmpty()) 437 if (!selector_.EnabledWorkQueuesEmpty())
429 return base::TimeDelta(); 438 return NextTaskDelay();
430 439
431 // Otherwise we need to find the shortest delay, if any. NB we don't need to 440 // 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 441 // call WakeupReadyDelayedQueues because it's assumed DelayTillNextTask will
433 // return base::TimeDelta>() if the delayed task is due to run now. 442 // return base::TimeDelta>() if the delayed task is due to run now.
434 base::Optional<base::TimeDelta> next_continuation; 443 base::Optional<NextTaskDelay> delay_till_next_task;
435 for (TimeDomain* time_domain : time_domains_) { 444 for (TimeDomain* time_domain : time_domains_) {
436 base::Optional<base::TimeDelta> continuation = 445 base::Optional<base::TimeDelta> delay =
437 time_domain->DelayTillNextTask(lazy_now); 446 time_domain->DelayTillNextTask(lazy_now);
438 if (!continuation) 447 if (!delay)
439 continue; 448 continue;
440 if (!next_continuation || next_continuation.value() > continuation.value()) 449
441 next_continuation = continuation; 450 NextTaskDelay task_delay = (delay.value() == base::TimeDelta())
451 ? NextTaskDelay()
452 : NextTaskDelay(delay.value(), time_domain);
453
454 if (!delay_till_next_task || delay_till_next_task > task_delay)
455 delay_till_next_task = task_delay;
442 } 456 }
443 return next_continuation; 457 return delay_till_next_task;
444 } 458 }
445 459
446 bool TaskQueueManager::SelectWorkQueueToService( 460 bool TaskQueueManager::SelectWorkQueueToService(
447 internal::WorkQueue** out_work_queue) { 461 internal::WorkQueue** out_work_queue) {
448 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); 462 bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
449 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 463 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
450 disabled_by_default_tracing_category_, "TaskQueueManager", this, 464 disabled_by_default_tracing_category_, "TaskQueueManager", this,
451 AsValueWithSelectorResult(should_run, *out_work_queue)); 465 AsValueWithSelectorResult(should_run, *out_work_queue));
452 return should_run; 466 return should_run;
453 } 467 }
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { 705 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) {
692 TimeDomain* time_domain = queue->GetTimeDomain(); 706 TimeDomain* time_domain = queue->GetTimeDomain();
693 if (time_domain_now.find(time_domain) == time_domain_now.end()) 707 if (time_domain_now.find(time_domain) == time_domain_now.end())
694 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); 708 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now()));
695 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); 709 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]);
696 } 710 }
697 } 711 }
698 712
699 } // namespace scheduler 713 } // namespace scheduler
700 } // namespace blink 714 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698