Chromium Code Reviews| 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 disabled_by_default_verbose_tracing_category), | 68 disabled_by_default_verbose_tracing_category), |
| 69 currently_executing_task_queue_(nullptr), | 69 currently_executing_task_queue_(nullptr), |
| 70 observer_(nullptr), | 70 observer_(nullptr), |
| 71 deletion_sentinel_(new DeletionSentinel()), | 71 deletion_sentinel_(new DeletionSentinel()), |
| 72 weak_factory_(this) { | 72 weak_factory_(this) { |
| 73 DCHECK(delegate->RunsTasksOnCurrentThread()); | 73 DCHECK(delegate->RunsTasksOnCurrentThread()); |
| 74 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, | 74 TRACE_EVENT_OBJECT_CREATED_WITH_ID(disabled_by_default_tracing_category, |
| 75 "TaskQueueManager", this); | 75 "TaskQueueManager", this); |
| 76 selector_.SetTaskQueueSelectorObserver(this); | 76 selector_.SetTaskQueueSelectorObserver(this); |
| 77 | 77 |
| 78 from_main_thread_immediate_do_work_closure_ = | 78 delayed_do_work_closure_ = |
| 79 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), | 79 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true); |
| 80 base::TimeTicks(), true); | 80 immediate_do_work_closure_ = |
| 81 from_other_thread_immediate_do_work_closure_ = | 81 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false); |
| 82 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), | |
| 83 base::TimeTicks(), false); | |
| 84 | 82 |
| 85 // TODO(alexclarke): Change this to be a parameter that's passed in. | 83 // TODO(alexclarke): Change this to be a parameter that's passed in. |
| 86 RegisterTimeDomain(real_time_domain_.get()); | 84 RegisterTimeDomain(real_time_domain_.get()); |
| 87 | 85 |
| 88 delegate_->AddNestingObserver(this); | 86 delegate_->AddNestingObserver(this); |
| 89 } | 87 } |
| 90 | 88 |
| 91 TaskQueueManager::~TaskQueueManager() { | 89 TaskQueueManager::~TaskQueueManager() { |
| 92 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, | 90 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, |
| 93 "TaskQueueManager", this); | 91 "TaskQueueManager", this); |
| 94 | 92 |
| 95 while (!queues_.empty()) | 93 while (!queues_.empty()) |
| 96 (*queues_.begin())->UnregisterTaskQueue(); | 94 (*queues_.begin())->UnregisterTaskQueue(); |
| 97 | 95 |
| 98 selector_.SetTaskQueueSelectorObserver(nullptr); | 96 selector_.SetTaskQueueSelectorObserver(nullptr); |
| 99 | 97 |
| 100 delegate_->RemoveNestingObserver(this); | 98 delegate_->RemoveNestingObserver(this); |
| 101 } | 99 } |
| 102 | 100 |
| 103 TaskQueueManager::AnyThread::AnyThread() : other_thread_pending_wakeup(false) {} | 101 TaskQueueManager::AnyThread::AnyThread() |
| 102 : do_work_running_count(0), | |
| 103 immediate_do_work_posted_count(0), | |
| 104 is_nested(false) {} | |
| 104 | 105 |
| 105 void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) { | 106 void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) { |
| 106 time_domains_.insert(time_domain); | 107 time_domains_.insert(time_domain); |
| 107 time_domain->OnRegisterWithTaskQueueManager(this); | 108 time_domain->OnRegisterWithTaskQueueManager(this); |
| 108 } | 109 } |
| 109 | 110 |
| 110 void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) { | 111 void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) { |
| 111 time_domains_.erase(time_domain); | 112 time_domains_.erase(time_domain); |
| 112 } | 113 } |
| 113 | 114 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 176 } else { | 177 } else { |
| 177 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow(); | 178 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow(); |
| 178 time_domain->WakeupReadyDelayedQueues(&time_domain_lazy_now); | 179 time_domain->WakeupReadyDelayedQueues(&time_domain_lazy_now); |
| 179 } | 180 } |
| 180 } | 181 } |
| 181 } | 182 } |
| 182 | 183 |
| 183 void TaskQueueManager::OnBeginNestedMessageLoop() { | 184 void TaskQueueManager::OnBeginNestedMessageLoop() { |
| 184 // We just entered a nested message loop, make sure there's a DoWork posted or | 185 // We just entered a nested message loop, make sure there's a DoWork posted or |
| 185 // the system will grind to a halt. | 186 // the system will grind to a halt. |
| 186 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); | 187 { |
| 188 base::AutoLock lock(any_thread_lock_); | |
| 189 any_thread().immediate_do_work_posted_count++; | |
| 190 any_thread().is_nested = true; | |
| 191 } | |
| 192 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); | |
| 187 } | 193 } |
| 188 | 194 |
| 189 void TaskQueueManager::OnQueueHasIncomingImmediateWork( | 195 void TaskQueueManager::OnQueueHasIncomingImmediateWork( |
| 190 internal::TaskQueueImpl* queue, | 196 internal::TaskQueueImpl* queue, |
| 191 bool queue_is_blocked) { | 197 bool queue_is_blocked) { |
| 192 bool on_main_thread = delegate_->BelongsToCurrentThread(); | 198 MoveableAutoLock lock(any_thread_lock_); |
| 193 | 199 any_thread().has_incoming_immediate_work.insert(queue); |
| 194 { | 200 if (!queue_is_blocked) |
| 195 base::AutoLock lock(any_thread_lock_); | 201 MaybeScheduleImmediateWorkLocked(FROM_HERE, std::move(lock)); |
| 196 any_thread().has_incoming_immediate_work.insert(queue); | |
| 197 | |
| 198 if (queue_is_blocked) | |
| 199 return; | |
| 200 | |
| 201 // De-duplicate DoWork posts. | |
| 202 if (on_main_thread) { | |
| 203 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) | |
| 204 return; | |
| 205 } else { | |
| 206 if (any_thread().other_thread_pending_wakeup) | |
| 207 return; | |
| 208 any_thread().other_thread_pending_wakeup = true; | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 if (on_main_thread) { | |
| 213 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_); | |
| 214 } else { | |
| 215 delegate_->PostTask(FROM_HERE, | |
| 216 from_other_thread_immediate_do_work_closure_); | |
| 217 } | |
| 218 } | 202 } |
| 219 | 203 |
| 220 void TaskQueueManager::MaybeScheduleImmediateWork( | 204 void TaskQueueManager::MaybeScheduleImmediateWork( |
| 221 const tracked_objects::Location& from_here) { | 205 const tracked_objects::Location& from_here) { |
| 222 bool on_main_thread = delegate_->BelongsToCurrentThread(); | 206 MoveableAutoLock lock(any_thread_lock_); |
| 223 // De-duplicate DoWork posts. | 207 MaybeScheduleImmediateWorkLocked(from_here, std::move(lock)); |
| 224 if (on_main_thread) { | 208 } |
| 225 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) { | 209 |
| 210 void TaskQueueManager::MaybeScheduleImmediateWorkLocked( | |
| 211 const tracked_objects::Location& from_here, | |
| 212 MoveableAutoLock&& lock) { | |
| 213 { | |
| 214 MoveableAutoLock auto_lock(std::move(lock)); | |
| 215 // Unless we're nested, try to avoid posting redundant DoWorks. | |
| 216 if (!any_thread().is_nested && | |
| 217 (any_thread().do_work_running_count == 1 || | |
| 218 any_thread().immediate_do_work_posted_count > 0)) { | |
| 226 return; | 219 return; |
|
Sami
2017/01/26 12:29:17
Could we DCHECK here that ComputeDelayTillNextTask
alex clarke (OOO till 29th)
2017/01/26 15:22:38
Unfortunately ComputeDelayTillNextTaskLocked has s
| |
| 227 } | 220 } |
| 228 delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_); | 221 |
| 229 } else { | 222 any_thread().immediate_do_work_posted_count++; |
| 230 { | |
| 231 base::AutoLock lock(any_thread_lock_); | |
| 232 if (any_thread().other_thread_pending_wakeup) | |
| 233 return; | |
| 234 any_thread().other_thread_pending_wakeup = true; | |
| 235 } | |
| 236 delegate_->PostTask(from_here, | |
| 237 from_other_thread_immediate_do_work_closure_); | |
| 238 } | 223 } |
| 224 | |
| 225 TRACE_EVENT0(disabled_by_default_tracing_category_, | |
| 226 "TaskQueueManager::MaybeScheduleImmediateWorkLocked::PostTask"); | |
| 227 delegate_->PostTask(from_here, immediate_do_work_closure_); | |
| 239 } | 228 } |
| 240 | 229 |
| 241 void TaskQueueManager::MaybeScheduleDelayedWork( | 230 void TaskQueueManager::MaybeScheduleDelayedWork( |
| 242 const tracked_objects::Location& from_here, | 231 const tracked_objects::Location& from_here, |
| 243 base::TimeTicks now, | 232 base::TimeTicks now, |
| 244 base::TimeDelta delay) { | 233 base::TimeDelta delay) { |
| 245 DCHECK(main_thread_checker_.CalledOnValidThread()); | 234 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 246 DCHECK_GE(delay, base::TimeDelta()); | 235 DCHECK_GE(delay, base::TimeDelta()); |
| 236 { | |
| 237 base::AutoLock lock(any_thread_lock_); | |
| 247 | 238 |
| 248 // If there's a pending immediate DoWork then we rely on | 239 // Unless we're nested, don't post a delayed DoWork if there's an immediate |
| 249 // TryAdvanceTimeDomains getting the TimeDomain to call | 240 // DoWork in flight or we're inside a DoWork. We can rely on DoWork posting |
| 250 // MaybeScheduleDelayedWork again when the immediate DoWork is complete. | 241 // a delayed continuation as needed. |
| 251 if (main_thread_pending_wakeups_.find(base::TimeTicks()) != | 242 if (!any_thread().is_nested && |
| 252 main_thread_pending_wakeups_.end()) { | 243 (any_thread().immediate_do_work_posted_count > 0 || |
| 253 return; | 244 any_thread().do_work_running_count == 1)) { |
| 245 return; | |
|
Sami
2017/01/26 12:29:17
Similarly a DCHECK that verifies the continuation
alex clarke (OOO till 29th)
2017/01/26 15:22:38
Same problem here.
| |
| 246 } | |
| 254 } | 247 } |
| 248 | |
| 255 // De-duplicate DoWork posts. | 249 // De-duplicate DoWork posts. |
| 256 base::TimeTicks run_time = now + delay; | 250 base::TimeTicks run_time = now + delay; |
| 257 if (!main_thread_pending_wakeups_.empty() && | 251 if (next_delayed_do_work_ <= run_time && !next_delayed_do_work_.is_null()) |
| 258 *main_thread_pending_wakeups_.begin() <= run_time) { | |
| 259 return; | 252 return; |
| 260 } | 253 |
| 261 main_thread_pending_wakeups_.insert(run_time); | 254 TRACE_EVENT1(disabled_by_default_tracing_category_, |
| 255 "TaskQueueManager::MaybeScheduleDelayedWork::PostDelayedTask", | |
| 256 "delay_ms", delay.InMillisecondsF()); | |
| 257 | |
| 258 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); | |
| 259 next_delayed_do_work_ = run_time; | |
| 262 delegate_->PostDelayedTask( | 260 delegate_->PostDelayedTask( |
| 263 from_here, base::Bind(&TaskQueueManager::DoWork, | 261 from_here, cancelable_delayed_do_work_closure_.callback(), delay); |
| 264 weak_factory_.GetWeakPtr(), run_time, true), | |
| 265 delay); | |
| 266 } | 262 } |
| 267 | 263 |
| 268 void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) { | 264 void TaskQueueManager::DoWork(bool delayed) { |
| 269 DCHECK(main_thread_checker_.CalledOnValidThread()); | 265 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 270 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", | 266 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork", "delayed", |
| 271 "from_main_thread", from_main_thread); | 267 delayed); |
| 272 | 268 |
| 273 if (from_main_thread) { | 269 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); |
| 274 main_thread_pending_wakeups_.erase(run_time); | |
| 275 } else { | |
| 276 base::AutoLock lock(any_thread_lock_); | |
| 277 any_thread().other_thread_pending_wakeup = false; | |
| 278 } | |
| 279 | |
| 280 // Posting a DoWork while a DoWork is running leads to spurious DoWorks. | |
| 281 main_thread_pending_wakeups_.insert(base::TimeTicks()); | |
| 282 | |
| 283 bool is_nested = delegate_->IsNested(); | 270 bool is_nested = delegate_->IsNested(); |
| 284 if (!is_nested) | 271 if (!is_nested) |
| 285 queues_to_delete_.clear(); | 272 queues_to_delete_.clear(); |
| 286 | 273 |
| 287 LazyNow lazy_now(real_time_domain()->CreateLazyNow()); | 274 // This must be done before running any tasks because they could invoke a |
| 288 WakeupReadyDelayedQueues(&lazy_now); | 275 // nested message loop and we risk having a stale |next_delayed_do_work_|. |
| 276 if (delayed) | |
| 277 next_delayed_do_work_ = base::TimeTicks(); | |
| 289 | 278 |
| 290 for (int i = 0; i < work_batch_size_; i++) { | 279 for (int i = 0; i < work_batch_size_; i++) { |
| 291 std::unordered_set<internal::TaskQueueImpl*> queues_to_reload; | 280 std::unordered_set<internal::TaskQueueImpl*> queues_to_reload; |
| 292 | 281 |
| 293 { | 282 { |
| 294 base::AutoLock lock(any_thread_lock_); | 283 base::AutoLock lock(any_thread_lock_); |
| 284 any_thread().is_nested = is_nested; | |
|
Sami
2017/01/26 12:29:17
If I understood right, we only need to update this
alex clarke (OOO till 29th)
2017/01/26 15:22:37
Done.
| |
| 285 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); | |
| 286 | |
| 287 if (i == 0) { | |
| 288 any_thread().do_work_running_count++; | |
| 289 | |
| 290 if (!delayed) { | |
| 291 any_thread().immediate_do_work_posted_count--; | |
| 292 DCHECK_GE(any_thread().immediate_do_work_posted_count, 0); | |
| 293 } | |
| 294 } | |
| 295 std::swap(queues_to_reload, any_thread().has_incoming_immediate_work); | 295 std::swap(queues_to_reload, any_thread().has_incoming_immediate_work); |
| 296 } | 296 } |
| 297 | 297 |
| 298 // It's important we call ReloadEmptyWorkQueues out side of the lock to | 298 // It's important we call ReloadEmptyWorkQueues out side of the lock to |
| 299 // avoid a lock order inversion. | 299 // avoid a lock order inversion. |
| 300 ReloadEmptyWorkQueues(queues_to_reload); | 300 ReloadEmptyWorkQueues(queues_to_reload); |
| 301 | 301 |
| 302 internal::WorkQueue* work_queue; | 302 WakeupReadyDelayedQueues(&lazy_now); |
| 303 | |
| 304 internal::WorkQueue* work_queue = nullptr; | |
| 303 if (!SelectWorkQueueToService(&work_queue)) | 305 if (!SelectWorkQueueToService(&work_queue)) |
| 304 break; | 306 break; |
| 305 | 307 |
| 308 // NB this may unregister |work_queue|. | |
| 306 base::TimeTicks time_after_task; | 309 base::TimeTicks time_after_task; |
| 307 switch (ProcessTaskFromWorkQueue(work_queue, is_nested, lazy_now, | 310 switch (ProcessTaskFromWorkQueue(work_queue, is_nested, lazy_now, |
| 308 &time_after_task)) { | 311 &time_after_task)) { |
| 309 case ProcessTaskResult::DEFERRED: | 312 case ProcessTaskResult::DEFERRED: |
| 310 // If a task was deferred, try again with another task. | 313 // If a task was deferred, try again with another task. |
| 311 continue; | 314 continue; |
| 312 case ProcessTaskResult::EXECUTED: | 315 case ProcessTaskResult::EXECUTED: |
| 313 break; | 316 break; |
| 314 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: | 317 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: |
| 315 return; // The TaskQueueManager got deleted, we must bail out. | 318 return; // The TaskQueueManager got deleted, we must bail out. |
| 316 } | 319 } |
| 317 | 320 |
| 318 work_queue = nullptr; // The queue may have been unregistered. | |
| 319 | |
| 320 lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow() | 321 lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow() |
| 321 : LazyNow(time_after_task); | 322 : LazyNow(time_after_task); |
| 322 WakeupReadyDelayedQueues(&lazy_now); | |
| 323 | 323 |
| 324 // Only run a single task per batch in nested run loops so that we can | 324 // Only run a single task per batch in nested run loops so that we can |
| 325 // properly exit the nested loop when someone calls RunLoop::Quit(). | 325 // properly exit the nested loop when someone calls RunLoop::Quit(). |
| 326 if (is_nested) | 326 if (is_nested) |
| 327 break; | 327 break; |
| 328 } | 328 } |
| 329 | 329 |
| 330 main_thread_pending_wakeups_.erase(base::TimeTicks()); | |
| 331 | |
| 332 // TODO(alexclarke): Consider refactoring the above loop to terminate only | 330 // TODO(alexclarke): Consider refactoring the above loop to terminate only |
| 333 // when there's no more work left to be done, rather than posting a | 331 // when there's no more work left to be done, rather than posting a |
| 334 // continuation task. | 332 // continuation task. |
| 335 base::Optional<base::TimeDelta> next_delay = | |
| 336 ComputeDelayTillNextTask(&lazy_now); | |
| 337 | 333 |
| 338 if (!next_delay) | 334 { |
| 339 return; | 335 MoveableAutoLock lock(any_thread_lock_); |
| 336 base::Optional<base::TimeDelta> next_delay = | |
| 337 ComputeDelayTillNextTaskLocked(&lazy_now); | |
| 340 | 338 |
| 341 base::TimeDelta delay = next_delay.value(); | 339 any_thread().do_work_running_count--; |
| 342 if (delay.is_zero()) { | 340 DCHECK_GE(any_thread().do_work_running_count, 0); |
| 343 MaybeScheduleImmediateWork(FROM_HERE); | 341 |
| 344 } else { | 342 any_thread().is_nested = is_nested; |
| 345 MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay); | 343 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); |
| 344 | |
| 345 PostDoWorkContinuationLocked(next_delay, &lazy_now, std::move(lock)); | |
| 346 } | 346 } |
| 347 } | 347 } |
| 348 | 348 |
| 349 base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask( | 349 void TaskQueueManager::PostDoWorkContinuationLocked( |
| 350 LazyNow* lazy_now) { | 350 base::Optional<base::TimeDelta> next_delay, |
| 351 LazyNow* lazy_now, | |
| 352 MoveableAutoLock&& lock) { | |
| 353 DCHECK(main_thread_checker_.CalledOnValidThread()); | |
| 354 base::TimeDelta delay; | |
| 355 | |
| 356 { | |
| 357 MoveableAutoLock auto_lock(std::move(lock)); | |
| 358 | |
| 359 // If there are no tasks left then we don't need to post a continuation. | |
| 360 if (!next_delay) { | |
| 361 // If there's a pending delayed DoWork, cancel it because it's not needed. | |
| 362 if (!next_delayed_do_work_.is_null()) { | |
| 363 next_delayed_do_work_ = base::TimeTicks(); | |
| 364 cancelable_delayed_do_work_closure_.Cancel(); | |
| 365 } | |
| 366 return; | |
| 367 } | |
| 368 | |
| 369 // If an immediate DoWork is posted, we don't need to post a continuation. | |
| 370 if (any_thread().immediate_do_work_posted_count > 0) | |
| 371 return; | |
| 372 | |
| 373 delay = next_delay.value(); | |
| 374 | |
| 375 // This isn't supposed to happen, but in case it does convert to | |
| 376 // non-delayed. | |
| 377 if (delay < base::TimeDelta()) | |
| 378 delay = base::TimeDelta(); | |
| 379 | |
| 380 if (delay.is_zero()) { | |
| 381 // If a delayed DoWork is pending then we don't need to post a | |
| 382 // continuation because it should run immediately. | |
| 383 if (!next_delayed_do_work_.is_null() && | |
| 384 next_delayed_do_work_ <= lazy_now->Now()) { | |
| 385 return; | |
| 386 } | |
| 387 | |
| 388 any_thread().immediate_do_work_posted_count++; | |
| 389 } else { | |
| 390 base::TimeTicks run_time = lazy_now->Now() + delay; | |
| 391 if (next_delayed_do_work_ == run_time) | |
| 392 return; | |
| 393 | |
| 394 next_delayed_do_work_ = run_time; | |
| 395 } | |
| 396 } | |
| 397 | |
| 398 // We avoid holding |any_thread_lock_| while posting the task. | |
| 399 if (delay.is_zero()) { | |
| 400 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_); | |
| 401 } else { | |
| 402 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_); | |
| 403 delegate_->PostDelayedTask( | |
| 404 FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay); | |
| 405 } | |
| 406 } | |
| 407 | |
| 408 base::Optional<base::TimeDelta> | |
| 409 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) { | |
| 351 DCHECK(main_thread_checker_.CalledOnValidThread()); | 410 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 352 | 411 |
| 353 std::unordered_set<internal::TaskQueueImpl*> queues_to_reload; | 412 // Unfortunately because |any_thread_lock_| is held it's not safe to call |
|
Sami
2017/01/26 12:29:17
I guess we could call ReloadWorkQueues() right bef
alex clarke (OOO till 29th)
2017/01/26 15:22:38
So in theory the check now is entirely equivalent
| |
| 354 { | 413 // ReloadEmptyWorkQueues here (possible lock order inversion). |
| 355 base::AutoLock lock(any_thread_lock_); | 414 for (const internal::TaskQueueImpl* queue : |
| 356 std::swap(queues_to_reload, any_thread().has_incoming_immediate_work); | 415 any_thread().has_incoming_immediate_work) { |
| 416 if (queue->IsQueueEnabled() && !queue->HasFence()) | |
| 417 return base::TimeDelta(); | |
| 357 } | 418 } |
| 358 | 419 |
| 359 // It's important we call ReloadEmptyWorkQueues out side of the lock to | |
| 360 // avoid a lock order inversion. | |
| 361 ReloadEmptyWorkQueues(queues_to_reload); | |
| 362 | |
| 363 // If the selector has non-empty queues we trivially know there is immediate | 420 // If the selector has non-empty queues we trivially know there is immediate |
| 364 // work to be done. | 421 // work to be done. |
| 365 if (!selector_.EnabledWorkQueuesEmpty()) | 422 if (!selector_.EnabledWorkQueuesEmpty()) |
| 366 return base::TimeDelta(); | 423 return base::TimeDelta(); |
| 367 | 424 |
| 368 // Otherwise we need to find the shortest delay, if any. | 425 // Otherwise we need to find the shortest delay, if any. |
| 369 base::Optional<base::TimeDelta> next_continuation; | 426 base::Optional<base::TimeDelta> next_continuation; |
| 370 for (TimeDomain* time_domain : time_domains_) { | 427 for (TimeDomain* time_domain : time_domains_) { |
| 371 base::Optional<base::TimeDelta> continuation = | 428 base::Optional<base::TimeDelta> continuation = |
| 372 time_domain->DelayTillNextTask(lazy_now); | 429 time_domain->DelayTillNextTask(lazy_now); |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 selected_work_queue->task_queue()->GetName()); | 628 selected_work_queue->task_queue()->GetName()); |
| 572 state->SetString("work_queue_name", selected_work_queue->name()); | 629 state->SetString("work_queue_name", selected_work_queue->name()); |
| 573 } | 630 } |
| 574 | 631 |
| 575 state->BeginArray("time_domains"); | 632 state->BeginArray("time_domains"); |
| 576 for (auto* time_domain : time_domains_) | 633 for (auto* time_domain : time_domains_) |
| 577 time_domain->AsValueInto(state.get()); | 634 time_domain->AsValueInto(state.get()); |
| 578 state->EndArray(); | 635 state->EndArray(); |
| 579 { | 636 { |
| 580 base::AutoLock lock(any_thread_lock_); | 637 base::AutoLock lock(any_thread_lock_); |
| 638 state->SetBoolean("is_nested", any_thread().is_nested); | |
| 639 state->SetInteger("do_work_running_count", | |
| 640 any_thread().do_work_running_count); | |
| 641 state->SetInteger("immediate_do_work_posted_count", | |
| 642 any_thread().immediate_do_work_posted_count); | |
| 643 | |
| 581 state->BeginArray("has_incoming_immediate_work"); | 644 state->BeginArray("has_incoming_immediate_work"); |
| 582 for (internal::TaskQueueImpl* task_queue : | 645 for (internal::TaskQueueImpl* task_queue : |
| 583 any_thread().has_incoming_immediate_work) { | 646 any_thread().has_incoming_immediate_work) { |
| 584 state->AppendString(task_queue->GetName()); | 647 state->AppendString(task_queue->GetName()); |
| 585 } | 648 } |
| 586 state->EndArray(); | 649 state->EndArray(); |
| 587 } | 650 } |
| 588 return std::move(state); | 651 return std::move(state); |
| 589 } | 652 } |
| 590 | 653 |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 621 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { | 684 for (const scoped_refptr<internal::TaskQueueImpl>& queue : queues_) { |
| 622 TimeDomain* time_domain = queue->GetTimeDomain(); | 685 TimeDomain* time_domain = queue->GetTimeDomain(); |
| 623 if (time_domain_now.find(time_domain) == time_domain_now.end()) | 686 if (time_domain_now.find(time_domain) == time_domain_now.end()) |
| 624 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); | 687 time_domain_now.insert(std::make_pair(time_domain, time_domain->Now())); |
| 625 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); | 688 queue->SweepCanceledDelayedTasks(time_domain_now[time_domain]); |
| 626 } | 689 } |
| 627 } | 690 } |
| 628 | 691 |
| 629 } // namespace scheduler | 692 } // namespace scheduler |
| 630 } // namespace blink | 693 } // namespace blink |
| OLD | NEW |