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

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

Issue 2359493002: Prevent redundant DoWorks due to canceled delayed tasks (v2) (Closed)
Patch Set: Added a test and removed some code we probably don't need. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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_impl.h" 5 #include "platform/scheduler/base/task_queue_impl.h"
6 6
7 #include "base/trace_event/blame_context.h" 7 #include "base/trace_event/blame_context.h"
8 #include "platform/scheduler/base/task_queue_manager.h" 8 #include "platform/scheduler/base/task_queue_manager.h"
9 #include "platform/scheduler/base/task_queue_manager_delegate.h" 9 #include "platform/scheduler/base/task_queue_manager_delegate.h"
10 #include "platform/scheduler/base/time_domain.h" 10 #include "platform/scheduler/base/time_domain.h"
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 PushOntoDelayedIncomingQueueLocked( 209 PushOntoDelayedIncomingQueueLocked(
210 Task(from_here, task, time_domain_delayed_run_time, sequence_number, 210 Task(from_here, task, time_domain_delayed_run_time, sequence_number,
211 task_type != TaskType::NON_NESTABLE)); 211 task_type != TaskType::NON_NESTABLE));
212 } 212 }
213 return true; 213 return true;
214 } 214 }
215 215
216 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( 216 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
217 Task pending_task, base::TimeTicks now) { 217 Task pending_task, base::TimeTicks now) {
218 main_thread_only().task_queue_manager->DidQueueTask(pending_task); 218 main_thread_only().task_queue_manager->DidQueueTask(pending_task);
219 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
219 220
220 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. 221 // If |pending_task| is at the head of the queue, then make sure a wakeup
221 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; 222 // is requested.
222 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); 223 if (pending_task.delayed_run_time ==
Sami 2016/09/22 11:20:54 Looks like a use-after-move.
alex clarke (OOO till 29th) 2016/09/22 16:24:20 Done.
223 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, 224 main_thread_only().delayed_incoming_queue.top().delayed_run_time) {
224 now); 225 main_thread_only().time_domain->ScheduleDelayedWork(
226 this, pending_task.delayed_run_time, now);
227 }
228
225 TraceQueueSize(false); 229 TraceQueueSize(false);
226 } 230 }
227 231
228 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { 232 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) {
229 any_thread().task_queue_manager->DidQueueTask(pending_task); 233 any_thread().task_queue_manager->DidQueueTask(pending_task);
230 234
231 int thread_hop_task_sequence_number = 235 int thread_hop_task_sequence_number =
232 any_thread().task_queue_manager->GetNextSequenceNumber(); 236 any_thread().task_queue_manager->GetNextSequenceNumber();
233 PushOntoImmediateIncomingQueueLocked( 237 PushOntoImmediateIncomingQueueLocked(
234 FROM_HERE, 238 FROM_HERE,
235 base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, 239 base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this,
236 base::Passed(&pending_task)), 240 base::Passed(&pending_task)),
237 base::TimeTicks(), 241 base::TimeTicks(),
238 thread_hop_task_sequence_number, 242 thread_hop_task_sequence_number,
239 false); 243 false);
240 } 244 }
241 245
246 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
247 DCHECK(main_thread_checker_.CalledOnValidThread());
248 base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
249 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now();
250 if (delayed_run_time < time_domain_now) {
251 // If |delayed_run_time| is in the past then push it onto the work queue
252 // immediately. To ensure the right task ordering we need to temporarily
253 // push it onto the |delayed_incoming_queue|.
254 delayed_run_time = time_domain_now;
255 pending_task.delayed_run_time = time_domain_now;
256 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
257 LazyNow lazy_now(time_domain_now);
258 WakeUpForDelayedWork(&lazy_now);
259 } else {
260 // If |delayed_run_time| is in the future we can queue it as normal.
261 PushOntoDelayedIncomingQueueFromMainThread(std::move(pending_task),
262 time_domain_now);
263 }
264 TraceQueueSize(false);
265 }
266
242 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( 267 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(
243 const tracked_objects::Location& posted_from, 268 const tracked_objects::Location& posted_from,
244 const base::Closure& task, 269 const base::Closure& task,
245 base::TimeTicks desired_run_time, 270 base::TimeTicks desired_run_time,
246 EnqueueOrder sequence_number, 271 EnqueueOrder sequence_number,
247 bool nestable) { 272 bool nestable) {
248 if (any_thread().immediate_incoming_queue.empty()) 273 if (any_thread().immediate_incoming_queue.empty())
249 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); 274 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
250 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make 275 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make
251 // it run. 276 // it run.
252 if (any_thread().immediate_incoming_queue.empty()) { 277 if (any_thread().immediate_incoming_queue.empty()) {
253 // There's no point posting a DoWork for a disabled queue, however we can 278 // There's no point posting a DoWork for a disabled queue, however we can
254 // only tell if it's disabled from the main thread. 279 // only tell if it's disabled from the main thread.
255 if (base::PlatformThread::CurrentId() == thread_id_) { 280 if (base::PlatformThread::CurrentId() == thread_id_) {
256 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) 281 if (main_thread_only().is_enabled && !BlockedByFenceLocked())
257 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); 282 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
258 } else { 283 } else {
259 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); 284 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE);
260 } 285 }
261 } 286 }
262 any_thread().immediate_incoming_queue.emplace( 287 any_thread().immediate_incoming_queue.emplace(
263 posted_from, task, desired_run_time, sequence_number, nestable, sequence_n umber); 288 posted_from, task, desired_run_time, sequence_number, nestable, sequence_n umber);
264 any_thread().task_queue_manager->DidQueueTask( any_thread().immediate_incoming _queue.back()); 289 any_thread().task_queue_manager->DidQueueTask( any_thread().immediate_incoming _queue.back());
265 TraceQueueSize(true); 290 TraceQueueSize(true);
266 } 291 }
267 292
268 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
269 DCHECK(main_thread_checker_.CalledOnValidThread());
270 base::TimeTicks delayed_run_time = pending_task.delayed_run_time;
271 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now();
272 // Make sure |delayed_run_time| isn't in the past.
273 if (delayed_run_time < time_domain_now) {
274 delayed_run_time = time_domain_now;
275 pending_task.delayed_run_time = time_domain_now;
276 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
277 LazyNow lazy_now(time_domain_now);
278 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now);
279 } else {
280 main_thread_only().delayed_incoming_queue.push(std::move(pending_task));
281 main_thread_only().time_domain->ScheduleDelayedWork(
282 this, delayed_run_time, main_thread_only().time_domain->Now());
283 }
284 TraceQueueSize(false);
285 }
286
287 void TaskQueueImpl::SetQueueEnabled(bool enabled) { 293 void TaskQueueImpl::SetQueueEnabled(bool enabled) {
288 if (main_thread_only().is_enabled == enabled) 294 if (main_thread_only().is_enabled == enabled)
289 return; 295 return;
290 main_thread_only().is_enabled = enabled; 296 main_thread_only().is_enabled = enabled;
291 if (!main_thread_only().task_queue_manager) 297 if (!main_thread_only().task_queue_manager)
292 return; 298 return;
293 if (enabled) { 299 if (enabled) {
294 // Note it's the job of the selector to tell the TaskQueueManager if 300 // Note it's the job of the selector to tell the TaskQueueManager if
295 // a DoWork needs posting. 301 // a DoWork needs posting.
296 main_thread_only().task_queue_manager->selector_.EnableQueue(this); 302 main_thread_only().task_queue_manager->selector_.EnableQueue(this);
(...skipping 30 matching lines...) Expand all
327 main_thread_only().delayed_incoming_queue.top().delayed_run_time <= 333 main_thread_only().delayed_incoming_queue.top().delayed_run_time <=
328 main_thread_only().time_domain->CreateLazyNow().Now()) { 334 main_thread_only().time_domain->CreateLazyNow().Now()) {
329 return true; 335 return true;
330 } 336 }
331 337
332 // Finally tasks on |immediate_incoming_queue| count as immediate work. 338 // Finally tasks on |immediate_incoming_queue| count as immediate work.
333 base::AutoLock lock(any_thread_lock_); 339 base::AutoLock lock(any_thread_lock_);
334 return !any_thread().immediate_incoming_queue.empty(); 340 return !any_thread().immediate_incoming_queue.empty();
335 } 341 }
336 342
337 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { 343 void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) {
338 // Enqueue all delayed tasks that should be running now, skipping any that 344 // Enqueue all delayed tasks that should be running now, skipping any that
339 // have been canceled. 345 // have been canceled.
340 while (!main_thread_only().delayed_incoming_queue.empty()) { 346 while (!main_thread_only().delayed_incoming_queue.empty()) {
341 // TODO(alexclarke): Use extract() when C++17 is allowed.
342 Task& task = 347 Task& task =
343 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); 348 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top());
344 if (task.task.IsCancelled()) { 349 if (task.task.IsCancelled()) {
345 main_thread_only().delayed_incoming_queue.pop(); 350 main_thread_only().delayed_incoming_queue.pop();
346 continue; 351 continue;
347 } 352 }
348 if (task.delayed_run_time > lazy_now->Now()) 353 if (task.delayed_run_time > lazy_now->Now())
349 break; 354 break;
350 task.set_enqueue_order( 355 task.set_enqueue_order(
351 main_thread_only().task_queue_manager->GetNextSequenceNumber()); 356 main_thread_only().task_queue_manager->GetNextSequenceNumber());
352 main_thread_only().delayed_work_queue->Push(std::move(task)); 357 main_thread_only().delayed_work_queue->Push(std::move(task));
353 main_thread_only().delayed_incoming_queue.pop(); 358 main_thread_only().delayed_incoming_queue.pop();
354 } 359 }
360
361 // Make sure the next wake up is scheduled.
362 if (!main_thread_only().delayed_incoming_queue.empty()) {
363 main_thread_only().time_domain->ScheduleDelayedWork(
364 this, main_thread_only().delayed_incoming_queue.top().delayed_run_time,
365 lazy_now->Now());
366 }
355 } 367 }
356 368
357 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { 369 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() {
358 if (!main_thread_only().task_queue_manager) 370 if (!main_thread_only().task_queue_manager)
359 return false; 371 return false;
360 372
361 if (!main_thread_only().immediate_work_queue->Empty()) 373 if (!main_thread_only().immediate_work_queue->Empty())
362 return true; 374 return true;
363 375
364 base::AutoLock lock(any_thread_lock_); 376 base::AutoLock lock(any_thread_lock_);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 main_thread_only().immediate_work_queue->Size()); 457 main_thread_only().immediate_work_queue->Size());
446 state->SetInteger("delayed_work_queue_size", 458 state->SetInteger("delayed_work_queue_size",
447 main_thread_only().delayed_work_queue->Size()); 459 main_thread_only().delayed_work_queue->Size());
448 if (!main_thread_only().delayed_incoming_queue.empty()) { 460 if (!main_thread_only().delayed_incoming_queue.empty()) {
449 base::TimeDelta delay_to_next_task = 461 base::TimeDelta delay_to_next_task =
450 (main_thread_only().delayed_incoming_queue.top().delayed_run_time - 462 (main_thread_only().delayed_incoming_queue.top().delayed_run_time -
451 main_thread_only().time_domain->CreateLazyNow().Now()); 463 main_thread_only().time_domain->CreateLazyNow().Now());
452 state->SetDouble("delay_to_next_task_ms", 464 state->SetDouble("delay_to_next_task_ms",
453 delay_to_next_task.InMillisecondsF()); 465 delay_to_next_task.InMillisecondsF());
454 } 466 }
467 if (main_thread_only().current_fence)
468 state->SetInteger("current_fence", main_thread_only().current_fence);
455 if (verbose_tracing_enabled) { 469 if (verbose_tracing_enabled) {
456 state->BeginArray("immediate_incoming_queue"); 470 state->BeginArray("immediate_incoming_queue");
457 QueueAsValueInto(any_thread().immediate_incoming_queue, state); 471 QueueAsValueInto(any_thread().immediate_incoming_queue, state);
458 state->EndArray(); 472 state->EndArray();
459 state->BeginArray("delayed_work_queue"); 473 state->BeginArray("delayed_work_queue");
460 main_thread_only().delayed_work_queue->AsValueInto(state); 474 main_thread_only().delayed_work_queue->AsValueInto(state);
461 state->EndArray(); 475 state->EndArray();
462 state->BeginArray("immediate_work_queue"); 476 state->BeginArray("immediate_work_queue");
463 main_thread_only().immediate_work_queue->AsValueInto(state); 477 main_thread_only().immediate_work_queue->AsValueInto(state);
464 state->EndArray(); 478 state->EndArray();
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
670 state->SetBoolean("is_cancelled", task.task.IsCancelled()); 684 state->SetBoolean("is_cancelled", task.task.IsCancelled());
671 state->SetDouble( 685 state->SetDouble(
672 "delayed_run_time", 686 "delayed_run_time",
673 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); 687 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L);
674 state->EndDictionary(); 688 state->EndDictionary();
675 } 689 }
676 690
677 } // namespace internal 691 } // namespace internal
678 } // namespace scheduler 692 } // namespace scheduler
679 } // namespace blink 693 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698