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 |