OLD | NEW |
---|---|
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" |
11 #include "platform/scheduler/base/work_queue.h" | 11 #include "platform/scheduler/base/work_queue.h" |
12 | 12 |
13 namespace blink { | 13 namespace blink { |
14 namespace scheduler { | 14 namespace scheduler { |
15 | 15 |
16 TaskQueue::TaskHandle::TaskHandle() : enqueue_order_(0), sequence_number_(0) {} | |
17 | |
18 TaskQueue::TaskHandle::TaskHandle(TaskQueue* task_queue, uint64_t enqueue_order) | |
19 : enqueue_order_(enqueue_order), | |
20 #if DCHECK_IS_ON() | |
21 task_queue_(task_queue), | |
22 #endif | |
23 sequence_number_(0) { | |
24 DCHECK_GT(enqueue_order, 0ull); | |
25 } | |
26 | |
27 TaskQueue::TaskHandle::TaskHandle(TaskQueue* task_queue, | |
28 base::TimeTicks scheduled_run_time, | |
29 int sequence_number) | |
30 : enqueue_order_(0), | |
31 scheduled_run_time_(scheduled_run_time), | |
32 #if DCHECK_IS_ON() | |
33 task_queue_(task_queue), | |
34 #endif | |
35 sequence_number_(sequence_number) { | |
36 DCHECK(!scheduled_run_time.is_null()); | |
37 } | |
38 | |
39 TaskQueue::TaskHandle::operator bool() const { | |
40 return !scheduled_run_time_.is_null() || | |
41 internal::EnqueueOrderGenerator::IsValidEnqueueOrder(enqueue_order_); | |
42 } | |
43 | |
44 namespace internal { | 16 namespace internal { |
45 | 17 |
46 TaskQueueImpl::TaskQueueImpl( | 18 TaskQueueImpl::TaskQueueImpl( |
47 TaskQueueManager* task_queue_manager, | 19 TaskQueueManager* task_queue_manager, |
48 TimeDomain* time_domain, | 20 TimeDomain* time_domain, |
49 const Spec& spec, | 21 const Spec& spec, |
50 const char* disabled_by_default_tracing_category, | 22 const char* disabled_by_default_tracing_category, |
51 const char* disabled_by_default_verbose_tracing_category) | 23 const char* disabled_by_default_verbose_tracing_category) |
52 : thread_id_(base::PlatformThread::CurrentId()), | 24 : thread_id_(base::PlatformThread::CurrentId()), |
53 any_thread_(task_queue_manager, time_domain), | 25 any_thread_(task_queue_manager, time_domain), |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
109 bool nestable, | 81 bool nestable, |
110 EnqueueOrder enqueue_order) | 82 EnqueueOrder enqueue_order) |
111 : PendingTask(posted_from, task, desired_run_time, nestable), | 83 : PendingTask(posted_from, task, desired_run_time, nestable), |
112 #ifndef NDEBUG | 84 #ifndef NDEBUG |
113 enqueue_order_set_(true), | 85 enqueue_order_set_(true), |
114 #endif | 86 #endif |
115 enqueue_order_(enqueue_order) { | 87 enqueue_order_(enqueue_order) { |
116 sequence_num = sequence_number; | 88 sequence_num = sequence_number; |
117 } | 89 } |
118 | 90 |
119 // static | |
120 TaskQueueImpl::Task TaskQueueImpl::Task::CreateFakeTaskFromHandle( | |
121 const TaskHandle& handle) { | |
122 if (handle.scheduled_run_time_.is_null()) { | |
123 // It's an immediate task. | |
124 return Task(tracked_objects::Location(), base::Closure(), | |
125 handle.scheduled_run_time_, handle.sequence_number_, false, | |
126 handle.enqueue_order_); | |
127 } else { | |
128 // It's a delayed task. | |
129 DCHECK_EQ(0ull, handle.enqueue_order_); | |
130 return Task(tracked_objects::Location(), base::Closure(), | |
131 handle.scheduled_run_time_, handle.sequence_number_, false); | |
132 } | |
133 } | |
134 | |
135 bool TaskQueueImpl::Task::DelayedRunTimeComparator::operator()( | |
136 const Task& a, | |
137 const Task& b) const { | |
138 if (a.delayed_run_time < b.delayed_run_time) | |
139 return true; | |
140 | |
141 if (a.delayed_run_time > b.delayed_run_time) | |
142 return false; | |
143 | |
144 // If the times happen to match, then we use the sequence number to decide. | |
145 // Compare the difference to support integer roll-over. | |
146 return (a.sequence_num - b.sequence_num) < 0; | |
147 } | |
148 | |
149 // static | |
150 bool TaskQueueImpl::Task::EnqueueOrderComparatorFn(const Task& a, | |
151 const Task& b) { | |
152 return a.enqueue_order() < b.enqueue_order(); | |
153 } | |
154 | |
155 // static | |
156 bool TaskQueueImpl::Task::DelayedRunTimeComparatorFn(const Task& a, | |
157 const Task& b) { | |
158 if (a.delayed_run_time < b.delayed_run_time) | |
159 return true; | |
160 | |
161 if (a.delayed_run_time > b.delayed_run_time) | |
162 return false; | |
163 | |
164 // If the times happen to match, then we use the sequence number to decide. | |
165 // Compare the difference to support integer roll-over. | |
166 return (a.sequence_num - b.sequence_num) < 0; | |
167 } | |
168 | |
169 TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, | 91 TaskQueueImpl::AnyThread::AnyThread(TaskQueueManager* task_queue_manager, |
170 TimeDomain* time_domain) | 92 TimeDomain* time_domain) |
171 : task_queue_manager(task_queue_manager), | 93 : task_queue_manager(task_queue_manager), time_domain(time_domain) {} |
172 time_domain(time_domain), | |
173 immediate_incoming_queue(&TaskQueueImpl::Task::EnqueueOrderComparatorFn) { | |
174 } | |
175 | 94 |
176 TaskQueueImpl::AnyThread::~AnyThread() {} | 95 TaskQueueImpl::AnyThread::~AnyThread() {} |
177 | 96 |
178 TaskQueueImpl::MainThreadOnly::MainThreadOnly( | 97 TaskQueueImpl::MainThreadOnly::MainThreadOnly( |
179 TaskQueueManager* task_queue_manager, | 98 TaskQueueManager* task_queue_manager, |
180 TaskQueueImpl* task_queue, | 99 TaskQueueImpl* task_queue, |
181 TimeDomain* time_domain) | 100 TimeDomain* time_domain) |
182 : task_queue_manager(task_queue_manager), | 101 : task_queue_manager(task_queue_manager), |
183 time_domain(time_domain), | 102 time_domain(time_domain), |
184 delayed_work_queue( | 103 delayed_work_queue(new WorkQueue(task_queue, "delayed")), |
185 new WorkQueue(task_queue, | 104 immediate_work_queue(new WorkQueue(task_queue, "immediate")), |
186 "delayed", | |
187 &TaskQueueImpl::Task::DelayedRunTimeComparatorFn)), | |
188 immediate_work_queue( | |
189 new WorkQueue(task_queue, | |
190 "immediate", | |
191 &TaskQueueImpl::Task::EnqueueOrderComparatorFn)), | |
192 set_index(0), | 105 set_index(0), |
193 is_enabled(true), | 106 is_enabled(true), |
194 blame_context(nullptr), | 107 blame_context(nullptr), |
195 current_fence(0) {} | 108 current_fence(0) {} |
196 | 109 |
197 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} | 110 TaskQueueImpl::MainThreadOnly::~MainThreadOnly() {} |
198 | 111 |
199 void TaskQueueImpl::UnregisterTaskQueue() { | 112 void TaskQueueImpl::UnregisterTaskQueue() { |
200 base::AutoLock lock(any_thread_lock_); | 113 base::AutoLock lock(any_thread_lock_); |
201 if (main_thread_only().time_domain) | 114 if (main_thread_only().time_domain) |
202 main_thread_only().time_domain->UnregisterQueue(this); | 115 main_thread_only().time_domain->UnregisterQueue(this); |
203 if (!any_thread().task_queue_manager) | 116 if (!any_thread().task_queue_manager) |
204 return; | 117 return; |
205 any_thread().time_domain = nullptr; | 118 any_thread().time_domain = nullptr; |
206 main_thread_only().time_domain = nullptr; | 119 main_thread_only().time_domain = nullptr; |
207 any_thread().task_queue_manager->UnregisterTaskQueue(this); | 120 any_thread().task_queue_manager->UnregisterTaskQueue(this); |
208 | 121 |
209 any_thread().task_queue_manager = nullptr; | 122 any_thread().task_queue_manager = nullptr; |
210 main_thread_only().task_queue_manager = nullptr; | 123 main_thread_only().task_queue_manager = nullptr; |
211 main_thread_only().delayed_incoming_queue.clear(); | 124 main_thread_only().delayed_incoming_queue = std::priority_queue<Task>(); |
212 any_thread().immediate_incoming_queue.clear(); | 125 any_thread().immediate_incoming_queue = std::queue<Task>(); |
213 main_thread_only().immediate_work_queue.reset(); | 126 main_thread_only().immediate_work_queue.reset(); |
214 main_thread_only().delayed_work_queue.reset(); | 127 main_thread_only().delayed_work_queue.reset(); |
215 } | 128 } |
216 | 129 |
217 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { | 130 bool TaskQueueImpl::RunsTasksOnCurrentThread() const { |
218 base::AutoLock lock(any_thread_lock_); | 131 base::AutoLock lock(any_thread_lock_); |
219 return base::PlatformThread::CurrentId() == thread_id_; | 132 return base::PlatformThread::CurrentId() == thread_id_; |
220 } | 133 } |
221 | 134 |
222 TaskQueue::TaskHandle TaskQueueImpl::PostCancellableDelayedTask( | |
223 const tracked_objects::Location& from_here, | |
224 const base::Closure& task, | |
225 base::TimeDelta delay) { | |
226 if (!main_thread_only().task_queue_manager) | |
227 return TaskHandle(); | |
228 | |
229 EnqueueOrder sequence_number = | |
230 main_thread_only().task_queue_manager->GetNextSequenceNumber(); | |
231 | |
232 if (delay.is_zero()) { | |
233 base::AutoLock lock(any_thread_lock_); | |
234 PushOntoImmediateIncomingQueueLocked( | |
235 Task(from_here, task, base::TimeTicks(), sequence_number, true, | |
236 sequence_number)); | |
237 | |
238 return TaskHandle(this, sequence_number); | |
239 } else { | |
240 DCHECK_GT(delay, base::TimeDelta()); | |
241 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); | |
242 base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; | |
243 PushOntoDelayedIncomingQueueFromMainThread( | |
244 Task(from_here, task, time_domain_delayed_run_time, sequence_number, | |
245 true), | |
246 time_domain_now); | |
247 | |
248 return TaskHandle(this, time_domain_delayed_run_time, sequence_number); | |
249 } | |
250 } | |
251 | |
252 bool TaskQueueImpl::CancelTask(const TaskQueue::TaskHandle& handle) { | |
253 if (!handle) | |
254 return false; | |
255 | |
256 // If the TaskQueueManager has gone away, pretend we have canceled the task | |
257 // because this simplifies logic in TimerBase::stop. | |
258 if (!main_thread_only().task_queue_manager) | |
259 return true; | |
260 | |
261 #if DCHECK_IS_ON() | |
262 DCHECK_EQ(handle.task_queue_, this); | |
263 #endif | |
264 | |
265 Task fake_task = Task::CreateFakeTaskFromHandle(handle); | |
266 if (handle.scheduled_run_time_.is_null()) { | |
267 // It's an immediate task. | |
268 if (main_thread_only().immediate_work_queue->CancelTask(fake_task)) | |
269 return true; | |
270 | |
271 base::AutoLock lock(any_thread_lock_); | |
272 return any_thread().immediate_incoming_queue.erase(fake_task) > 0; | |
273 } else { | |
274 // It's a delayed task. | |
275 DelayedRunTimeQueue::iterator it = | |
276 main_thread_only().delayed_incoming_queue.find(fake_task); | |
277 if (it != main_thread_only().delayed_incoming_queue.end()) { | |
278 // It's safe to remove the wakeup from the TimeDomain only if this task's | |
279 // scheduled run time was unique within the queue. | |
280 bool can_cancel_timedomain_wakeup = true; | |
281 if (it != main_thread_only().delayed_incoming_queue.begin()) { | |
282 DelayedRunTimeQueue::iterator before = it; | |
283 before--; | |
284 if (before->delayed_run_time == handle.scheduled_run_time_) | |
285 can_cancel_timedomain_wakeup = false; | |
286 } | |
287 if (can_cancel_timedomain_wakeup) { | |
288 DelayedRunTimeQueue::iterator after = it; | |
289 after++; | |
290 if (after != main_thread_only().delayed_incoming_queue.end() && | |
291 after->delayed_run_time == handle.scheduled_run_time_) { | |
292 can_cancel_timedomain_wakeup = false; | |
293 } | |
294 } | |
295 if (can_cancel_timedomain_wakeup) { | |
296 main_thread_only().time_domain->CancelDelayedWork( | |
297 this, handle.scheduled_run_time_); | |
298 } | |
299 | |
300 main_thread_only().delayed_incoming_queue.erase(it); | |
301 return true; | |
302 } | |
303 | |
304 return main_thread_only().delayed_work_queue->CancelTask(fake_task); | |
305 } | |
306 } | |
307 | |
308 bool TaskQueueImpl::IsTaskPending(const TaskQueue::TaskHandle& handle) const { | |
309 if (!handle) | |
310 return false; | |
311 | |
312 // If the TaskQueueManager has gone away the task got cancelled. | |
313 if (!main_thread_only().task_queue_manager) | |
314 return false; | |
315 | |
316 #if DCHECK_IS_ON() | |
317 DCHECK_EQ(handle.task_queue_, this); | |
318 #endif | |
319 | |
320 Task fake_task = Task::CreateFakeTaskFromHandle(handle); | |
321 if (handle.scheduled_run_time_.is_null()) { | |
322 // It's an immediate task. | |
323 if (main_thread_only().immediate_work_queue->IsTaskPending(fake_task)) | |
324 return true; | |
325 | |
326 base::AutoLock lock(any_thread_lock_); | |
327 return any_thread().immediate_incoming_queue.find(fake_task) != | |
328 any_thread().immediate_incoming_queue.end(); | |
329 } else { | |
330 // It's a delayed task. | |
331 DelayedRunTimeQueue::iterator it = | |
332 main_thread_only().delayed_incoming_queue.find(fake_task); | |
333 if (it != main_thread_only().delayed_incoming_queue.end()) | |
334 return true; | |
335 | |
336 return main_thread_only().delayed_work_queue->IsTaskPending(fake_task); | |
337 } | |
338 } | |
339 | 135 |
340 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, | 136 bool TaskQueueImpl::PostDelayedTask(const tracked_objects::Location& from_here, |
341 const base::Closure& task, | 137 const base::Closure& task, |
342 base::TimeDelta delay) { | 138 base::TimeDelta delay) { |
343 if (delay.is_zero()) | 139 if (delay.is_zero()) |
344 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); | 140 return PostImmediateTaskImpl(from_here, task, TaskType::NORMAL); |
345 | 141 |
346 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); | 142 return PostDelayedTaskImpl(from_here, task, delay, TaskType::NORMAL); |
347 } | 143 } |
348 | 144 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
412 task_type != TaskType::NON_NESTABLE)); | 208 task_type != TaskType::NON_NESTABLE)); |
413 } | 209 } |
414 return true; | 210 return true; |
415 } | 211 } |
416 | 212 |
417 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( | 213 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( |
418 Task pending_task, | 214 Task pending_task, |
419 base::TimeTicks now) { | 215 base::TimeTicks now) { |
420 main_thread_only().task_queue_manager->DidQueueTask(pending_task); | 216 main_thread_only().task_queue_manager->DidQueueTask(pending_task); |
421 | 217 |
422 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. | 218 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue.. |
Sami
2016/09/08 16:35:02
nit: extra '.'?
alex clarke (OOO till 29th)
2016/09/08 16:43:28
Done.
| |
423 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 219 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
424 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 220 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
425 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, | 221 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, |
426 now); | 222 now); |
427 TraceQueueSize(false); | 223 TraceQueueSize(false); |
428 } | 224 } |
429 | 225 |
430 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { | 226 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { |
431 any_thread().task_queue_manager->DidQueueTask(pending_task); | 227 any_thread().task_queue_manager->DidQueueTask(pending_task); |
432 | 228 |
433 int thread_hop_task_sequence_number = | 229 int thread_hop_task_sequence_number = |
434 any_thread().task_queue_manager->GetNextSequenceNumber(); | 230 any_thread().task_queue_manager->GetNextSequenceNumber(); |
(...skipping 13 matching lines...) Expand all Loading... | |
448 // There's no point posting a DoWork for a disabled queue, however we can | 244 // There's no point posting a DoWork for a disabled queue, however we can |
449 // only tell if it's disabled from the main thread. | 245 // only tell if it's disabled from the main thread. |
450 if (base::PlatformThread::CurrentId() == thread_id_) { | 246 if (base::PlatformThread::CurrentId() == thread_id_) { |
451 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) | 247 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) |
452 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 248 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
453 } else { | 249 } else { |
454 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 250 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
455 } | 251 } |
456 } | 252 } |
457 any_thread().task_queue_manager->DidQueueTask(pending_task); | 253 any_thread().task_queue_manager->DidQueueTask(pending_task); |
458 // We expect |pending_task| to be inserted at the end. Amoritized O(1). | 254 any_thread().immediate_incoming_queue.push(std::move(pending_task)); |
459 any_thread().immediate_incoming_queue.insert( | |
460 any_thread().immediate_incoming_queue.end(), | |
461 std::move(pending_task)); | |
462 DCHECK_EQ(pending_task.enqueue_order(), | |
463 any_thread().immediate_incoming_queue.rbegin()->enqueue_order()); | |
464 TraceQueueSize(true); | 255 TraceQueueSize(true); |
465 } | 256 } |
466 | 257 |
467 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { | 258 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { |
468 DCHECK(main_thread_checker_.CalledOnValidThread()); | 259 DCHECK(main_thread_checker_.CalledOnValidThread()); |
469 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 260 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
470 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); | 261 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); |
471 // Make sure |delayed_run_time| isn't in the past. | 262 // Make sure |delayed_run_time| isn't in the past. |
472 if (delayed_run_time < time_domain_now) { | 263 if (delayed_run_time < time_domain_now) { |
473 delayed_run_time = time_domain_now; | 264 delayed_run_time = time_domain_now; |
474 pending_task.delayed_run_time = time_domain_now; | 265 pending_task.delayed_run_time = time_domain_now; |
475 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 266 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
476 LazyNow lazy_now(time_domain_now); | 267 LazyNow lazy_now(time_domain_now); |
477 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); | 268 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); |
478 } else { | 269 } else { |
479 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 270 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
480 main_thread_only().time_domain->ScheduleDelayedWork( | 271 main_thread_only().time_domain->ScheduleDelayedWork( |
481 this, delayed_run_time, main_thread_only().time_domain->Now()); | 272 this, delayed_run_time, main_thread_only().time_domain->Now()); |
482 } | 273 } |
483 TraceQueueSize(false); | 274 TraceQueueSize(false); |
484 } | 275 } |
485 | 276 |
486 void TaskQueueImpl::SetQueueEnabled(bool enabled) { | 277 void TaskQueueImpl::SetQueueEnabled(bool enabled) { |
487 if (main_thread_only().is_enabled == enabled) | 278 if (main_thread_only().is_enabled == enabled) |
488 return; | 279 return; |
489 main_thread_only().is_enabled = enabled; | 280 main_thread_only().is_enabled = enabled; |
490 if (!main_thread_only().task_queue_manager) | 281 if (!main_thread_only().task_queue_manager) |
491 return; | 282 return; |
492 if (enabled) { | 283 if (enabled) { |
493 // Note it's the job of the selector to tell the TaskQueueManager if | 284 // Note it's the job of the selector to tell the TaskQueueManager if |
494 // a DoWork needs posting. | 285 // a DoWork needs posting. |
495 main_thread_only().task_queue_manager->selector_.EnableQueue(this); | 286 main_thread_only().task_queue_manager->selector_.EnableQueue(this); |
496 } else { | 287 } else { |
497 main_thread_only().task_queue_manager->selector_.DisableQueue(this); | 288 main_thread_only().task_queue_manager->selector_.DisableQueue(this); |
498 } | 289 } |
499 } | 290 } |
500 | 291 |
501 bool TaskQueueImpl::IsQueueEnabled() const { | 292 bool TaskQueueImpl::IsQueueEnabled() const { |
502 return main_thread_only().is_enabled; | 293 return main_thread_only().is_enabled; |
503 } | 294 } |
504 | 295 |
505 bool TaskQueueImpl::IsEmpty() const { | 296 bool TaskQueueImpl::IsEmpty() const { |
506 if (!main_thread_only().delayed_work_queue->Empty() || | 297 if (!main_thread_only().delayed_work_queue->Empty() || |
298 !main_thread_only().delayed_incoming_queue.empty() || | |
507 !main_thread_only().immediate_work_queue->Empty()) { | 299 !main_thread_only().immediate_work_queue->Empty()) { |
508 return false; | 300 return false; |
509 } | 301 } |
510 | 302 |
511 base::AutoLock lock(any_thread_lock_); | 303 base::AutoLock lock(any_thread_lock_); |
512 return any_thread().immediate_incoming_queue.empty() && | 304 return any_thread().immediate_incoming_queue.empty(); |
513 main_thread_only().delayed_incoming_queue.empty(); | |
514 } | 305 } |
515 | 306 |
516 bool TaskQueueImpl::HasPendingImmediateWork() const { | 307 bool TaskQueueImpl::HasPendingImmediateWork() const { |
517 // Any work queue tasks count as immediate work. | 308 // Any work queue tasks count as immediate work. |
518 if (!main_thread_only().delayed_work_queue->Empty() || | 309 if (!main_thread_only().delayed_work_queue->Empty() || |
519 !main_thread_only().immediate_work_queue->Empty()) { | 310 !main_thread_only().immediate_work_queue->Empty()) { |
520 return true; | 311 return true; |
521 } | 312 } |
522 | 313 |
523 // Tasks on |delayed_incoming_queue| that could run now, count as | 314 // Tasks on |delayed_incoming_queue| that could run now, count as |
524 // immediate work. | 315 // immediate work. |
525 if (!main_thread_only().delayed_incoming_queue.empty() && | 316 if (!main_thread_only().delayed_incoming_queue.empty() && |
526 main_thread_only().delayed_incoming_queue.begin()->delayed_run_time <= | 317 main_thread_only().delayed_incoming_queue.top().delayed_run_time <= |
527 main_thread_only().time_domain->CreateLazyNow().Now()) { | 318 main_thread_only().time_domain->CreateLazyNow().Now()) { |
528 return true; | 319 return true; |
529 } | 320 } |
530 | 321 |
531 // Finally tasks on |immediate_incoming_queue| count as immediate work. | 322 // Finally tasks on |immediate_incoming_queue| count as immediate work. |
532 base::AutoLock lock(any_thread_lock_); | 323 base::AutoLock lock(any_thread_lock_); |
533 return !any_thread().immediate_incoming_queue.empty(); | 324 return !any_thread().immediate_incoming_queue.empty(); |
534 } | 325 } |
535 | 326 |
536 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { | 327 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { |
537 // Enqueue all delayed tasks that should be running now. | 328 // Enqueue all delayed tasks that should be running now. |
538 while (!main_thread_only().delayed_incoming_queue.empty()) { | 329 while (!main_thread_only().delayed_incoming_queue.empty()) { |
539 DelayedRunTimeQueue::iterator next_task = | 330 // TODO(alexclarke): Use extract() when C++17 is allowed. |
540 main_thread_only().delayed_incoming_queue.begin(); | 331 Task& task = |
541 if (next_task->delayed_run_time > lazy_now->Now()) | 332 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); |
333 if (task.task.IsCancelled()) { | |
334 main_thread_only().delayed_incoming_queue.pop(); | |
335 continue; | |
336 } | |
337 if (task.delayed_run_time > lazy_now->Now()) | |
542 break; | 338 break; |
543 // TODO(alexclarke): Use extract() when C++17 is allowed. | |
544 Task& task = const_cast<Task&>(*next_task); | |
545 task.set_enqueue_order( | 339 task.set_enqueue_order( |
546 main_thread_only().task_queue_manager->GetNextSequenceNumber()); | 340 main_thread_only().task_queue_manager->GetNextSequenceNumber()); |
547 main_thread_only().delayed_work_queue->Push(std::move(task)); | 341 main_thread_only().delayed_work_queue->Push(std::move(task)); |
548 main_thread_only().delayed_incoming_queue.erase(next_task); | 342 main_thread_only().delayed_incoming_queue.pop(); |
549 } | 343 } |
550 } | 344 } |
551 | 345 |
552 void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now) { | 346 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { |
553 if (!main_thread_only().task_queue_manager) | 347 if (!main_thread_only().task_queue_manager) |
554 return; | 348 return false; |
555 MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); | |
556 TraceQueueSize(false); | |
557 } | |
558 | 349 |
559 void TaskQueueImpl::UpdateImmediateWorkQueue() { | 350 if (!main_thread_only().immediate_work_queue->Empty()) |
560 DCHECK(main_thread_only().immediate_work_queue->Empty()); | 351 return true; |
352 | |
561 base::AutoLock lock(any_thread_lock_); | 353 base::AutoLock lock(any_thread_lock_); |
562 if (!main_thread_only().task_queue_manager) | |
563 return; | |
564 | |
565 main_thread_only().immediate_work_queue->SwapLocked( | 354 main_thread_only().immediate_work_queue->SwapLocked( |
566 any_thread().immediate_incoming_queue); | 355 any_thread().immediate_incoming_queue); |
567 | 356 // |immediate_work_queue| is now empty so updates are no longer required. |
568 // |any_thread().immediate_incoming_queue| is now empty so | 357 return false; |
569 // TimeDomain::UpdateQueues no longer needs to consider this queue for | |
570 // reloading. | |
571 main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); | |
572 } | 358 } |
573 | 359 |
574 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { | 360 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
575 bool is_tracing; | 361 bool is_tracing; |
576 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, | 362 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, |
577 &is_tracing); | 363 &is_tracing); |
578 if (!is_tracing) | 364 if (!is_tracing) |
579 return; | 365 return; |
580 | 366 |
581 // It's only safe to access the work queues from the main thread. | 367 // It's only safe to access the work queues from the main thread. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
643 state->SetInteger("immediate_incoming_queue_size", | 429 state->SetInteger("immediate_incoming_queue_size", |
644 any_thread().immediate_incoming_queue.size()); | 430 any_thread().immediate_incoming_queue.size()); |
645 state->SetInteger("delayed_incoming_queue_size", | 431 state->SetInteger("delayed_incoming_queue_size", |
646 main_thread_only().delayed_incoming_queue.size()); | 432 main_thread_only().delayed_incoming_queue.size()); |
647 state->SetInteger("immediate_work_queue_size", | 433 state->SetInteger("immediate_work_queue_size", |
648 main_thread_only().immediate_work_queue->Size()); | 434 main_thread_only().immediate_work_queue->Size()); |
649 state->SetInteger("delayed_work_queue_size", | 435 state->SetInteger("delayed_work_queue_size", |
650 main_thread_only().delayed_work_queue->Size()); | 436 main_thread_only().delayed_work_queue->Size()); |
651 if (!main_thread_only().delayed_incoming_queue.empty()) { | 437 if (!main_thread_only().delayed_incoming_queue.empty()) { |
652 base::TimeDelta delay_to_next_task = | 438 base::TimeDelta delay_to_next_task = |
653 (main_thread_only().delayed_incoming_queue.begin()->delayed_run_time - | 439 (main_thread_only().delayed_incoming_queue.top().delayed_run_time - |
654 main_thread_only().time_domain->CreateLazyNow().Now()); | 440 main_thread_only().time_domain->CreateLazyNow().Now()); |
655 state->SetDouble("delay_to_next_task_ms", | 441 state->SetDouble("delay_to_next_task_ms", |
656 delay_to_next_task.InMillisecondsF()); | 442 delay_to_next_task.InMillisecondsF()); |
657 } | 443 } |
658 if (verbose_tracing_enabled) { | 444 if (verbose_tracing_enabled) { |
659 state->BeginArray("immediate_incoming_queue"); | 445 state->BeginArray("immediate_incoming_queue"); |
660 QueueAsValueInto(any_thread().immediate_incoming_queue, state); | 446 QueueAsValueInto(any_thread().immediate_incoming_queue, state); |
661 state->EndArray(); | 447 state->EndArray(); |
662 state->BeginArray("delayed_work_queue"); | 448 state->BeginArray("delayed_work_queue"); |
663 main_thread_only().delayed_work_queue->AsValueInto(state); | 449 main_thread_only().delayed_work_queue->AsValueInto(state); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
746 // Tasks posted after this point will have a strictly higher enqueue order | 532 // Tasks posted after this point will have a strictly higher enqueue order |
747 // and will be blocked from running. | 533 // and will be blocked from running. |
748 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( | 534 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( |
749 main_thread_only().current_fence); | 535 main_thread_only().current_fence); |
750 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( | 536 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( |
751 main_thread_only().current_fence); | 537 main_thread_only().current_fence); |
752 | 538 |
753 if (!task_unblocked && previous_fence) { | 539 if (!task_unblocked && previous_fence) { |
754 base::AutoLock lock(any_thread_lock_); | 540 base::AutoLock lock(any_thread_lock_); |
755 if (!any_thread().immediate_incoming_queue.empty() && | 541 if (!any_thread().immediate_incoming_queue.empty() && |
756 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 542 any_thread().immediate_incoming_queue.front().enqueue_order() > |
757 previous_fence && | 543 previous_fence && |
758 any_thread().immediate_incoming_queue.begin()->enqueue_order() < | 544 any_thread().immediate_incoming_queue.front().enqueue_order() < |
759 main_thread_only().current_fence) { | 545 main_thread_only().current_fence) { |
760 task_unblocked = true; | 546 task_unblocked = true; |
761 } | 547 } |
762 } | 548 } |
763 | 549 |
764 if (main_thread_only().is_enabled && task_unblocked) { | 550 if (main_thread_only().is_enabled && task_unblocked) { |
765 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 551 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
766 FROM_HERE); | 552 FROM_HERE); |
767 } | 553 } |
768 } | 554 } |
769 | 555 |
770 void TaskQueueImpl::RemoveFence() { | 556 void TaskQueueImpl::RemoveFence() { |
771 if (!main_thread_only().task_queue_manager) | 557 if (!main_thread_only().task_queue_manager) |
772 return; | 558 return; |
773 | 559 |
774 EnqueueOrder previous_fence = main_thread_only().current_fence; | 560 EnqueueOrder previous_fence = main_thread_only().current_fence; |
775 main_thread_only().current_fence = 0; | 561 main_thread_only().current_fence = 0; |
776 | 562 |
777 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); | 563 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); |
778 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); | 564 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); |
779 | 565 |
780 if (!task_unblocked && previous_fence) { | 566 if (!task_unblocked && previous_fence) { |
781 base::AutoLock lock(any_thread_lock_); | 567 base::AutoLock lock(any_thread_lock_); |
782 if (!any_thread().immediate_incoming_queue.empty() && | 568 if (!any_thread().immediate_incoming_queue.empty() && |
783 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 569 any_thread().immediate_incoming_queue.front().enqueue_order() > |
784 previous_fence) { | 570 previous_fence) { |
785 task_unblocked = true; | 571 task_unblocked = true; |
786 } | 572 } |
787 } | 573 } |
788 | 574 |
789 if (main_thread_only().is_enabled && task_unblocked) { | 575 if (main_thread_only().is_enabled && task_unblocked) { |
790 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 576 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
791 FROM_HERE); | 577 FROM_HERE); |
792 } | 578 } |
793 } | 579 } |
794 | 580 |
795 bool TaskQueueImpl::BlockedByFence() const { | 581 bool TaskQueueImpl::BlockedByFence() const { |
796 if (!main_thread_only().current_fence) | 582 if (!main_thread_only().current_fence) |
797 return false; | 583 return false; |
798 | 584 |
799 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 585 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
800 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 586 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
801 return false; | 587 return false; |
802 } | 588 } |
803 | 589 |
804 base::AutoLock lock(any_thread_lock_); | 590 base::AutoLock lock(any_thread_lock_); |
805 if (any_thread().immediate_incoming_queue.empty()) | 591 if (any_thread().immediate_incoming_queue.empty()) |
806 return true; | 592 return true; |
807 | 593 |
808 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 594 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
809 main_thread_only().current_fence; | 595 main_thread_only().current_fence; |
810 } | 596 } |
811 | 597 |
812 bool TaskQueueImpl::BlockedByFenceLocked() const { | 598 bool TaskQueueImpl::BlockedByFenceLocked() const { |
813 if (!main_thread_only().current_fence) | 599 if (!main_thread_only().current_fence) |
814 return false; | 600 return false; |
815 | 601 |
816 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 602 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
817 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 603 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
818 return false; | 604 return false; |
819 } | 605 } |
820 | 606 |
821 if (any_thread().immediate_incoming_queue.empty()) | 607 if (any_thread().immediate_incoming_queue.empty()) |
822 return true; | 608 return true; |
823 | 609 |
824 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 610 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
825 main_thread_only().current_fence; | 611 main_thread_only().current_fence; |
826 } | 612 } |
827 | 613 |
828 // static | 614 // static |
829 void TaskQueueImpl::QueueAsValueInto(const ComparatorQueue& queue, | 615 void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue, |
830 base::trace_event::TracedValue* state) { | 616 base::trace_event::TracedValue* state) { |
831 for (const Task& task : queue) { | 617 // Remove const to search |queue| in the destructive manner. Restore the |
832 TaskAsValueInto(task, state); | 618 // content from |visited| later. |
619 std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue); | |
620 std::queue<Task> visited; | |
621 while (!mutable_queue->empty()) { | |
622 TaskAsValueInto(mutable_queue->front(), state); | |
623 visited.push(std::move(mutable_queue->front())); | |
624 mutable_queue->pop(); | |
833 } | 625 } |
626 *mutable_queue = std::move(visited); | |
834 } | 627 } |
835 | 628 |
836 // static | 629 // static |
837 void TaskQueueImpl::QueueAsValueInto(const DelayedRunTimeQueue& queue, | 630 void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue, |
838 base::trace_event::TracedValue* state) { | 631 base::trace_event::TracedValue* state) { |
839 for (const Task& task : queue) { | 632 // Remove const to search |queue| in the destructive manner. Restore the |
840 TaskAsValueInto(task, state); | 633 // content from |visited| later. |
634 std::priority_queue<Task>* mutable_queue = | |
635 const_cast<std::priority_queue<Task>*>(&queue); | |
636 std::priority_queue<Task> visited; | |
637 while (!mutable_queue->empty()) { | |
638 TaskAsValueInto(mutable_queue->top(), state); | |
639 visited.push(std::move(const_cast<Task&>(mutable_queue->top()))); | |
640 mutable_queue->pop(); | |
841 } | 641 } |
642 *mutable_queue = std::move(visited); | |
842 } | 643 } |
843 | 644 |
844 // static | 645 // static |
845 void TaskQueueImpl::TaskAsValueInto(const Task& task, | 646 void TaskQueueImpl::TaskAsValueInto(const Task& task, |
846 base::trace_event::TracedValue* state) { | 647 base::trace_event::TracedValue* state) { |
847 state->BeginDictionary(); | 648 state->BeginDictionary(); |
848 state->SetString("posted_from", task.posted_from.ToString()); | 649 state->SetString("posted_from", task.posted_from.ToString()); |
849 #ifndef NDEBUG | 650 #ifndef NDEBUG |
850 if (task.enqueue_order_set()) | 651 if (task.enqueue_order_set()) |
851 state->SetInteger("enqueue_order", task.enqueue_order()); | 652 state->SetInteger("enqueue_order", task.enqueue_order()); |
852 #else | 653 #else |
853 state->SetInteger("enqueue_order", task.enqueue_order()); | 654 state->SetInteger("enqueue_order", task.enqueue_order()); |
854 #endif | 655 #endif |
855 state->SetInteger("sequence_num", task.sequence_num); | 656 state->SetInteger("sequence_num", task.sequence_num); |
856 state->SetBoolean("nestable", task.nestable); | 657 state->SetBoolean("nestable", task.nestable); |
857 state->SetBoolean("is_high_res", task.is_high_res); | 658 state->SetBoolean("is_high_res", task.is_high_res); |
659 state->SetBoolean("is_cancelled", task.task.IsCancelled()); | |
858 state->SetDouble( | 660 state->SetDouble( |
859 "delayed_run_time", | 661 "delayed_run_time", |
860 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); | 662 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); |
861 state->EndDictionary(); | 663 state->EndDictionary(); |
862 } | 664 } |
863 | 665 |
864 } // namespace internal | 666 } // namespace internal |
865 } // namespace scheduler | 667 } // namespace scheduler |
866 } // namespace blink | 668 } // namespace blink |
OLD | NEW |