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 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |