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

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

Issue 2574363002: Revert of Scheduler refactoring to virtually elimate redundant DoWorks (Closed)
Patch Set: Created 4 years 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 } 51 }
52 52
53 TaskQueueManager::TaskQueueManager( 53 TaskQueueManager::TaskQueueManager(
54 scoped_refptr<TaskQueueManagerDelegate> delegate, 54 scoped_refptr<TaskQueueManagerDelegate> delegate,
55 const char* tracing_category, 55 const char* tracing_category,
56 const char* disabled_by_default_tracing_category, 56 const char* disabled_by_default_tracing_category,
57 const char* disabled_by_default_verbose_tracing_category) 57 const char* disabled_by_default_verbose_tracing_category)
58 : real_time_domain_(new RealTimeDomain(tracing_category)), 58 : real_time_domain_(new RealTimeDomain(tracing_category)),
59 delegate_(delegate), 59 delegate_(delegate),
60 task_was_run_on_quiescence_monitored_queue_(false), 60 task_was_run_on_quiescence_monitored_queue_(false),
61 record_task_delay_histograms_(true), 61 other_thread_pending_wakeup_(false),
62 work_batch_size_(1), 62 work_batch_size_(1),
63 task_count_(0), 63 task_count_(0),
64 tracing_category_(tracing_category), 64 tracing_category_(tracing_category),
65 disabled_by_default_tracing_category_( 65 disabled_by_default_tracing_category_(
66 disabled_by_default_tracing_category), 66 disabled_by_default_tracing_category),
67 disabled_by_default_verbose_tracing_category_( 67 disabled_by_default_verbose_tracing_category_(
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 delayed_do_work_closure_ = 78 from_main_thread_immediate_do_work_closure_ =
79 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true); 79 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
80 immediate_do_work_closure_ = 80 base::TimeTicks(), true);
81 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false); 81 from_other_thread_immediate_do_work_closure_ =
82 base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(),
83 base::TimeTicks(), false);
82 84
83 // TODO(alexclarke): Change this to be a parameter that's passed in. 85 // TODO(alexclarke): Change this to be a parameter that's passed in.
84 RegisterTimeDomain(real_time_domain_.get()); 86 RegisterTimeDomain(real_time_domain_.get());
85 87
86 delegate_->AddNestingObserver(this); 88 delegate_->AddNestingObserver(this);
87 } 89 }
88 90
89 TaskQueueManager::~TaskQueueManager() { 91 TaskQueueManager::~TaskQueueManager() {
90 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_, 92 TRACE_EVENT_OBJECT_DELETED_WITH_ID(disabled_by_default_tracing_category_,
91 "TaskQueueManager", this); 93 "TaskQueueManager", this);
92 94
93 while (!queues_.empty()) 95 while (!queues_.empty())
94 (*queues_.begin())->UnregisterTaskQueue(); 96 (*queues_.begin())->UnregisterTaskQueue();
95 97
96 selector_.SetTaskQueueSelectorObserver(nullptr); 98 selector_.SetTaskQueueSelectorObserver(nullptr);
97 99
98 delegate_->RemoveNestingObserver(this); 100 delegate_->RemoveNestingObserver(this);
99 } 101 }
100 102
101 TaskQueueManager::AnyThread::AnyThread()
102 : do_work_running_count(0),
103 immediate_do_work_posted_count(0),
104 is_nested(false) {}
105
106 void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) { 103 void TaskQueueManager::RegisterTimeDomain(TimeDomain* time_domain) {
107 time_domains_.insert(time_domain); 104 time_domains_.insert(time_domain);
108 time_domain->OnRegisterWithTaskQueueManager(this); 105 time_domain->OnRegisterWithTaskQueueManager(this);
109 } 106 }
110 107
111 void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) { 108 void TaskQueueManager::UnregisterTimeDomain(TimeDomain* time_domain) {
112 time_domains_.erase(time_domain); 109 time_domains_.erase(time_domain);
113 } 110 }
114 111
115 scoped_refptr<internal::TaskQueueImpl> TaskQueueManager::NewTaskQueue( 112 scoped_refptr<internal::TaskQueueImpl> TaskQueueManager::NewTaskQueue(
(...skipping 25 matching lines...) Expand all
141 DCHECK(main_thread_checker_.CalledOnValidThread()); 138 DCHECK(main_thread_checker_.CalledOnValidThread());
142 if (observer_) 139 if (observer_)
143 observer_->OnUnregisterTaskQueue(task_queue); 140 observer_->OnUnregisterTaskQueue(task_queue);
144 141
145 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being 142 // Add |task_queue| to |queues_to_delete_| so we can prevent it from being
146 // freed while any of our structures hold hold a raw pointer to it. 143 // freed while any of our structures hold hold a raw pointer to it.
147 queues_to_delete_.insert(task_queue); 144 queues_to_delete_.insert(task_queue);
148 queues_.erase(task_queue); 145 queues_.erase(task_queue);
149 146
150 selector_.RemoveQueue(task_queue.get()); 147 selector_.RemoveQueue(task_queue.get());
151
152 {
153 base::AutoLock lock(any_thread_lock_);
154 any_thread().has_incoming_immediate_work.erase(task_queue.get());
155 }
156 } 148 }
157 149
158 void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) { 150 void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) {
151 TRACE_EVENT0(disabled_by_default_tracing_category_,
152 "TaskQueueManager::UpdateWorkQueues");
153
159 for (TimeDomain* time_domain : time_domains_) { 154 for (TimeDomain* time_domain : time_domains_) {
160 if (time_domain == real_time_domain_.get()) { 155 LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get()
161 time_domain->WakeupReadyDelayedQueues(lazy_now); 156 ? lazy_now
162 continue; 157 : time_domain->CreateLazyNow();
163 } 158 time_domain->UpdateWorkQueues(lazy_now_in_domain);
164 LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
165 time_domain->WakeupReadyDelayedQueues(&time_domain_lazy_now);
166 } 159 }
167 } 160 }
168 161
169 void TaskQueueManager::OnBeginNestedMessageLoop() { 162 void TaskQueueManager::OnBeginNestedMessageLoop() {
170 // We just entered a nested message loop, make sure there's a DoWork posted or 163 // We just entered a nested message loop, make sure there's a DoWork posted or
171 // the system will grind to a halt. 164 // the system will grind to a halt.
172 { 165 delegate_->PostTask(FROM_HERE, from_main_thread_immediate_do_work_closure_);
173 base::AutoLock lock(any_thread_lock_);
174 any_thread().immediate_do_work_posted_count++;
175 any_thread().is_nested = true;
176 }
177 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_);
178 }
179
180 void TaskQueueManager::OnQueueHasImmediateWork(internal::TaskQueueImpl* queue,
181 bool ensure_do_work_posted) {
182 MoveableAutoLock lock(any_thread_lock_);
183 any_thread().has_incoming_immediate_work.insert(queue);
184 if (ensure_do_work_posted)
185 MaybeScheduleImmediateWorkLocked(FROM_HERE, std::move(lock));
186 }
187
188 void TaskQueueManager::NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked() {
189 for (internal::TaskQueueImpl* queue :
190 any_thread().has_incoming_immediate_work) {
191 queue->ReloadImmediateWorkQueueIfEmpty();
192 }
193 any_thread().has_incoming_immediate_work.clear();
194 } 166 }
195 167
196 void TaskQueueManager::MaybeScheduleImmediateWork( 168 void TaskQueueManager::MaybeScheduleImmediateWork(
197 const tracked_objects::Location& from_here) { 169 const tracked_objects::Location& from_here) {
198 MoveableAutoLock lock(any_thread_lock_); 170 bool on_main_thread = delegate_->BelongsToCurrentThread();
199 MaybeScheduleImmediateWorkLocked(from_here, std::move(lock)); 171 // De-duplicate DoWork posts.
200 } 172 if (on_main_thread) {
201 173 if (!main_thread_pending_wakeups_.insert(base::TimeTicks()).second) {
202 void TaskQueueManager::MaybeScheduleImmediateWorkLocked(
203 const tracked_objects::Location& from_here,
204 MoveableAutoLock&& lock) {
205 {
206 MoveableAutoLock auto_lock(std::move(lock));
207 // Unless we're nested, try to avoid posting redundant DoWorks.
208 if (!any_thread().is_nested &&
209 (any_thread().do_work_running_count == 1 ||
210 any_thread().immediate_do_work_posted_count > 0)) {
211 return; 174 return;
212 } 175 }
213 176 delegate_->PostTask(from_here, from_main_thread_immediate_do_work_closure_);
214 any_thread().immediate_do_work_posted_count++; 177 } else {
178 {
179 base::AutoLock lock(other_thread_lock_);
180 if (other_thread_pending_wakeup_)
181 return;
182 other_thread_pending_wakeup_ = true;
183 }
184 delegate_->PostTask(from_here,
185 from_other_thread_immediate_do_work_closure_);
215 } 186 }
216 delegate_->PostTask(from_here, immediate_do_work_closure_);
217 } 187 }
218 188
219 void TaskQueueManager::MaybeScheduleDelayedWork( 189 void TaskQueueManager::MaybeScheduleDelayedWork(
220 const tracked_objects::Location& from_here, 190 const tracked_objects::Location& from_here,
221 base::TimeTicks now, 191 base::TimeTicks now,
222 base::TimeDelta delay) { 192 base::TimeDelta delay) {
223 DCHECK(main_thread_checker_.CalledOnValidThread()); 193 DCHECK(main_thread_checker_.CalledOnValidThread());
224 DCHECK_GE(delay, base::TimeDelta()); 194 DCHECK_GE(delay, base::TimeDelta());
225 {
226 base::AutoLock lock(any_thread_lock_);
227 195
228 // Unless we're nested, don't post a delayed DoWork if there's an immediate 196 // If there's a pending immediate DoWork then we rely on
229 // DoWork in flight or we're inside a DoWork. We can rely on DoWork posting 197 // TryAdvanceTimeDomains getting the TimeDomain to call
230 // a delayed continuation as needed. 198 // MaybeScheduleDelayedWork again when the immediate DoWork is complete.
231 if (!any_thread().is_nested && 199 if (main_thread_pending_wakeups_.find(base::TimeTicks()) !=
232 (any_thread().immediate_do_work_posted_count > 0 || 200 main_thread_pending_wakeups_.end()) {
233 any_thread().do_work_running_count == 1)) { 201 return;
234 return; 202 }
235 } 203 // De-duplicate DoWork posts.
204 base::TimeTicks run_time = now + delay;
205 if (!main_thread_pending_wakeups_.empty() &&
206 *main_thread_pending_wakeups_.begin() <= run_time) {
207 return;
208 }
209 main_thread_pending_wakeups_.insert(run_time);
210 delegate_->PostDelayedTask(
211 from_here, base::Bind(&TaskQueueManager::DoWork,
212 weak_factory_.GetWeakPtr(), run_time, true),
213 delay);
214 }
215
216 void TaskQueueManager::DoWork(base::TimeTicks run_time, bool from_main_thread) {
217 DCHECK(main_thread_checker_.CalledOnValidThread());
218 TRACE_EVENT1(tracing_category_, "TaskQueueManager::DoWork",
219 "from_main_thread", from_main_thread);
220
221 if (from_main_thread) {
222 main_thread_pending_wakeups_.erase(run_time);
223 } else {
224 base::AutoLock lock(other_thread_lock_);
225 other_thread_pending_wakeup_ = false;
236 } 226 }
237 227
238 // De-duplicate DoWork posts. 228 // Posting a DoWork while a DoWork is running leads to spurious DoWorks.
239 base::TimeTicks run_time = now + delay; 229 main_thread_pending_wakeups_.insert(base::TimeTicks());
240 if (next_delayed_do_work_ <= run_time && !next_delayed_do_work_.is_null())
241 return;
242 230
243 TRACE_EVENT1(tracing_category_, "MaybeScheduleDelayedWorkInternal", 231 if (!delegate_->IsNested())
244 "delay_ms", delay.InMillisecondsF());
245
246 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
247 next_delayed_do_work_ = run_time;
248 delegate_->PostDelayedTask(
249 from_here, cancelable_delayed_do_work_closure_.callback(), delay);
250 }
251
252 void TaskQueueManager::DoWork(bool delayed) {
253 DCHECK(main_thread_checker_.CalledOnValidThread());
254 TRACE_EVENT1("tracing_category_", "TaskQueueManager::DoWork", "delayed",
255 delayed);
256 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
257
258 bool is_nested = delegate_->IsNested();
259 if (!is_nested)
260 queues_to_delete_.clear(); 232 queues_to_delete_.clear();
261 233
262 // This must be done before running any tasks because they could invoke a 234 LazyNow lazy_now(real_time_domain()->CreateLazyNow());
263 // nested message loop and we risk having a stale |next_delayed_do_work_|. 235 UpdateWorkQueues(lazy_now);
264 if (delayed)
265 next_delayed_do_work_ = base::TimeTicks();
266 236
267 for (int i = 0; i < work_batch_size_; i++) { 237 for (int i = 0; i < work_batch_size_; i++) {
268 { 238 internal::WorkQueue* work_queue;
269 base::AutoLock lock(any_thread_lock_);
270 any_thread().is_nested = is_nested;
271 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested());
272
273 if (i == 0) {
274 any_thread().do_work_running_count++;
275
276 if (!delayed) {
277 any_thread().immediate_do_work_posted_count--;
278 DCHECK_GE(any_thread().immediate_do_work_posted_count, 0);
279 }
280 }
281
282 NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked();
283 }
284
285 UpdateWorkQueues(&lazy_now);
286
287 internal::WorkQueue* work_queue = nullptr;
288 if (!SelectWorkQueueToService(&work_queue)) 239 if (!SelectWorkQueueToService(&work_queue))
289 break; 240 break;
290 241
291 // NB this may unregister the queue. 242 switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) {
292 switch (ProcessTaskFromWorkQueue(work_queue, is_nested, &lazy_now)) {
293 case ProcessTaskResult::DEFERRED: 243 case ProcessTaskResult::DEFERRED:
294 // If a task was deferred, try again with another task. 244 // If a task was deferred, try again with another task.
295 continue; 245 continue;
296 case ProcessTaskResult::EXECUTED: 246 case ProcessTaskResult::EXECUTED:
297 break; 247 break;
298 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED: 248 case ProcessTaskResult::TASK_QUEUE_MANAGER_DELETED:
299 return; // The TaskQueueManager got deleted, we must bail out. 249 return; // The TaskQueueManager got deleted, we must bail out.
300 } 250 }
301 251
252 work_queue = nullptr; // The queue may have been unregistered.
253
254 UpdateWorkQueues(lazy_now);
255
302 // Only run a single task per batch in nested run loops so that we can 256 // Only run a single task per batch in nested run loops so that we can
303 // properly exit the nested loop when someone calls RunLoop::Quit(). 257 // properly exit the nested loop when someone calls RunLoop::Quit().
304 if (is_nested) 258 if (delegate_->IsNested())
305 break; 259 break;
306 } 260 }
307 261
262 main_thread_pending_wakeups_.erase(base::TimeTicks());
263
308 // TODO(alexclarke): Consider refactoring the above loop to terminate only 264 // TODO(alexclarke): Consider refactoring the above loop to terminate only
309 // when there's no more work left to be done, rather than posting a 265 // when there's no more work left to be done, rather than posting a
310 // continuation task. 266 // continuation task.
311 267 if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains())
312 { 268 MaybeScheduleImmediateWork(FROM_HERE);
313 MoveableAutoLock lock(any_thread_lock_);
314 base::Optional<base::TimeDelta> next_delay =
315 ComputeDelayTillNextTaskLocked(&lazy_now);
316
317 any_thread().do_work_running_count--;
318 DCHECK_GE(any_thread().do_work_running_count, 0);
319
320 any_thread().is_nested = is_nested;
321 DCHECK_EQ(any_thread().is_nested, delegate_->IsNested());
322
323 PostDoWorkContinuationLocked(next_delay, &lazy_now, std::move(lock));
324 }
325 } 269 }
326 270
327 void TaskQueueManager::PostDoWorkContinuationLocked( 271 bool TaskQueueManager::TryAdvanceTimeDomains() {
328 base::Optional<base::TimeDelta> next_delay, 272 bool can_advance = false;
329 LazyNow* lazy_now, 273 for (TimeDomain* time_domain : time_domains_) {
330 MoveableAutoLock&& lock) { 274 can_advance |= time_domain->MaybeAdvanceTime();
331 base::TimeDelta delay;
332
333 {
334 MoveableAutoLock auto_lock(std::move(lock));
335
336 // If there are no tasks left then we don't need to post a continuation.
337 if (!next_delay) {
338 // If there's a pending delayed DoWork, cancel it because it's not needed.
339 if (!next_delayed_do_work_.is_null()) {
340 next_delayed_do_work_ = base::TimeTicks();
341 cancelable_delayed_do_work_closure_.Cancel();
342 }
343 return;
344 }
345
346 // If an immediate DoWork is posted, we don't need to post a continuation.
347 if (any_thread().immediate_do_work_posted_count > 0)
348 return;
349
350 delay = next_delay.value();
351
352 // This isn't supposed to happen, but in case it does convert to
353 // non-delayed.
354 if (delay < base::TimeDelta())
355 delay = base::TimeDelta();
356
357 if (delay.is_zero()) {
358 // If a delayed DoWork is pending then we don't need to post a
359 // continuation because it should run immediately.
360 if (!next_delayed_do_work_.is_null() &&
361 next_delayed_do_work_ <= lazy_now->Now()) {
362 return;
363 }
364
365 any_thread().immediate_do_work_posted_count++;
366 } else {
367 base::TimeTicks run_time = lazy_now->Now() + delay;
368 if (next_delayed_do_work_ == run_time)
369 return;
370
371 next_delayed_do_work_ = run_time;
372 }
373 } 275 }
374 276 return can_advance;
375 // We avoid holding |any_thread_lock_| while posting the task.
376 if (delay.is_zero()) {
377 delegate_->PostTask(FROM_HERE, immediate_do_work_closure_);
378 } else {
379 cancelable_delayed_do_work_closure_.Reset(delayed_do_work_closure_);
380 delegate_->PostDelayedTask(
381 FROM_HERE, cancelable_delayed_do_work_closure_.callback(), delay);
382 }
383 }
384
385 base::Optional<base::TimeDelta>
386 TaskQueueManager::ComputeDelayTillNextTaskLocked(LazyNow* lazy_now) {
387 NotifyQueuesOfIncomingImmediateWorkOnMainThreadLocked();
388
389 // If the selector has non-empty queues we trivially know there is immediate
390 // word to be done.
391 if (!selector_.EnabledWorkQueuesEmpty())
392 return base::TimeDelta();
393
394 UpdateWorkQueues(lazy_now);
395
396 // Otherwise we need to find the shortest delay, if any.
397 base::Optional<base::TimeDelta> next_continuation;
398 for (TimeDomain* time_domain : time_domains_) {
399 base::Optional<base::TimeDelta> continuation =
400 time_domain->DelayTillNextTask(lazy_now);
401 if (!continuation)
402 continue;
403 if (!next_continuation || next_continuation.value() > continuation.value())
404 next_continuation = continuation;
405 }
406 return next_continuation;
407 } 277 }
408 278
409 bool TaskQueueManager::SelectWorkQueueToService( 279 bool TaskQueueManager::SelectWorkQueueToService(
410 internal::WorkQueue** out_work_queue) { 280 internal::WorkQueue** out_work_queue) {
411 bool should_run = selector_.SelectWorkQueueToService(out_work_queue); 281 bool should_run = selector_.SelectWorkQueueToService(out_work_queue);
412 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( 282 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
413 disabled_by_default_tracing_category_, "TaskQueueManager", this, 283 disabled_by_default_tracing_category_, "TaskQueueManager", this,
414 AsValueWithSelectorResult(should_run, *out_work_queue)); 284 AsValueWithSelectorResult(should_run, *out_work_queue));
415 return should_run; 285 return should_run;
416 } 286 }
417 287
418 void TaskQueueManager::DidQueueTask( 288 void TaskQueueManager::DidQueueTask(
419 const internal::TaskQueueImpl::Task& pending_task) { 289 const internal::TaskQueueImpl::Task& pending_task) {
420 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task); 290 task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
421 } 291 }
422 292
423 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue( 293 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
424 internal::WorkQueue* work_queue, 294 internal::WorkQueue* work_queue,
425 bool is_nested,
426 LazyNow* lazy_now) { 295 LazyNow* lazy_now) {
427 DCHECK(main_thread_checker_.CalledOnValidThread()); 296 DCHECK(main_thread_checker_.CalledOnValidThread());
428 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_); 297 scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
429 internal::TaskQueueImpl::Task pending_task = 298 internal::TaskQueueImpl::Task pending_task =
430 work_queue->TakeTaskFromWorkQueue(); 299 work_queue->TakeTaskFromWorkQueue();
431 300
432 // It's possible the task was canceled, if so bail out. 301 // It's possible the task was canceled, if so bail out.
433 if (pending_task.task.IsCancelled()) 302 if (pending_task.task.IsCancelled())
434 return ProcessTaskResult::EXECUTED; 303 return ProcessTaskResult::EXECUTED;
435 304
436 internal::TaskQueueImpl* queue = work_queue->task_queue(); 305 internal::TaskQueueImpl* queue = work_queue->task_queue();
437 if (queue->GetQuiescenceMonitored()) 306 if (queue->GetQuiescenceMonitored())
438 task_was_run_on_quiescence_monitored_queue_ = true; 307 task_was_run_on_quiescence_monitored_queue_ = true;
439 308
440 if (!pending_task.nestable && is_nested) { 309 if (!pending_task.nestable && delegate_->IsNested()) {
441 // Defer non-nestable work to the main task runner. NOTE these tasks can be 310 // Defer non-nestable work to the main task runner. NOTE these tasks can be
442 // arbitrarily delayed so the additional delay should not be a problem. 311 // arbitrarily delayed so the additional delay should not be a problem.
443 // TODO(skyostil): Figure out a way to not forget which task queue the 312 // TODO(skyostil): Figure out a way to not forget which task queue the
444 // task is associated with. See http://crbug.com/522843. 313 // task is associated with. See http://crbug.com/522843.
445 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once 314 // TODO(tzik): Remove base::UnsafeConvertOnceClosureToRepeating once
446 // TaskRunners have migrated to OnceClosure. 315 // TaskRunners have migrated to OnceClosure.
447 delegate_->PostNonNestableTask( 316 delegate_->PostNonNestableTask(
448 pending_task.posted_from, 317 pending_task.posted_from,
449 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task))); 318 UnsafeConvertOnceClosureToRepeating(std::move(pending_task.task)));
450 return ProcessTaskResult::DEFERRED; 319 return ProcessTaskResult::DEFERRED;
451 } 320 }
452 321
453 if (record_task_delay_histograms_) 322 MaybeRecordTaskDelayHistograms(pending_task, queue);
454 MaybeRecordTaskDelayHistograms(pending_task, queue);
455 323
456 double task_start_time = 0; 324 double task_start_time = 0;
457 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue", 325 TRACE_TASK_EXECUTION("TaskQueueManager::ProcessTaskFromWorkQueue",
458 pending_task); 326 pending_task);
459 if (queue->GetShouldNotifyObservers()) { 327 if (queue->GetShouldNotifyObservers()) {
460 for (auto& observer : task_observers_) 328 for (auto& observer : task_observers_)
461 observer.WillProcessTask(pending_task); 329 observer.WillProcessTask(pending_task);
462 queue->NotifyWillProcessTask(pending_task); 330 queue->NotifyWillProcessTask(pending_task);
463 331
464 bool notify_time_observers = 332 bool notify_time_observers =
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 if (should_run) { 463 if (should_run) {
596 state->SetString("selected_queue", 464 state->SetString("selected_queue",
597 selected_work_queue->task_queue()->GetName()); 465 selected_work_queue->task_queue()->GetName());
598 state->SetString("work_queue_name", selected_work_queue->name()); 466 state->SetString("work_queue_name", selected_work_queue->name());
599 } 467 }
600 468
601 state->BeginArray("time_domains"); 469 state->BeginArray("time_domains");
602 for (auto* time_domain : time_domains_) 470 for (auto* time_domain : time_domains_)
603 time_domain->AsValueInto(state.get()); 471 time_domain->AsValueInto(state.get());
604 state->EndArray(); 472 state->EndArray();
605
606 {
607 base::AutoLock lock(any_thread_lock_);
608 state->SetBoolean("is_nested", any_thread().is_nested);
609 state->SetInteger("do_work_running_count",
610 any_thread().do_work_running_count);
611 state->SetInteger("immediate_do_work_posted_count",
612 any_thread().immediate_do_work_posted_count);
613 }
614 return std::move(state); 473 return std::move(state);
615 } 474 }
616 475
617 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { 476 void TaskQueueManager::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
618 DCHECK(main_thread_checker_.CalledOnValidThread()); 477 DCHECK(main_thread_checker_.CalledOnValidThread());
619 // Only schedule DoWork if there's something to do. 478 // Only schedule DoWork if there's something to do.
620 if (queue->HasPendingImmediateWork() && !queue->BlockedByFence()) 479 if (queue->HasPendingImmediateWork())
621 MaybeScheduleImmediateWork(FROM_HERE); 480 MaybeScheduleImmediateWork(FROM_HERE);
622 } 481 }
623 482
624 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue( 483 void TaskQueueManager::OnTriedToSelectBlockedWorkQueue(
625 internal::WorkQueue* work_queue) { 484 internal::WorkQueue* work_queue) {
626 DCHECK(main_thread_checker_.CalledOnValidThread()); 485 DCHECK(main_thread_checker_.CalledOnValidThread());
627 DCHECK(!work_queue->Empty()); 486 DCHECK(!work_queue->Empty());
628 if (observer_) { 487 if (observer_) {
629 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(), 488 observer_->OnTriedToExecuteBlockedTask(*work_queue->task_queue(),
630 *work_queue->GetFrontTask()); 489 *work_queue->GetFrontTask());
631 } 490 }
632 } 491 }
633 492
634 bool TaskQueueManager::HasImmediateWorkForTesting() const { 493 bool TaskQueueManager::HasImmediateWorkForTesting() const {
635 return !selector_.EnabledWorkQueuesEmpty(); 494 return !selector_.EnabledWorkQueuesEmpty();
636 } 495 }
637 496
638 void TaskQueueManager::SetRecordTaskDelayHistograms(
639 bool record_task_delay_histograms) {
640 DCHECK(main_thread_checker_.CalledOnValidThread());
641 record_task_delay_histograms_ = record_task_delay_histograms;
642 }
643
644 } // namespace scheduler 497 } // namespace scheduler
645 } // namespace blink 498 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698