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 12 matching lines...) Expand all Loading... |
361 const base::Closure& task, | 157 const base::Closure& task, |
362 TaskType task_type) { | 158 TaskType task_type) { |
363 base::AutoLock lock(any_thread_lock_); | 159 base::AutoLock lock(any_thread_lock_); |
364 if (!any_thread().task_queue_manager) | 160 if (!any_thread().task_queue_manager) |
365 return false; | 161 return false; |
366 | 162 |
367 EnqueueOrder sequence_number = | 163 EnqueueOrder sequence_number = |
368 any_thread().task_queue_manager->GetNextSequenceNumber(); | 164 any_thread().task_queue_manager->GetNextSequenceNumber(); |
369 | 165 |
370 PushOntoImmediateIncomingQueueLocked( | 166 PushOntoImmediateIncomingQueueLocked( |
371 Task(from_here, task, base::TimeTicks(), sequence_number, | 167 from_here, |
372 task_type != TaskType::NON_NESTABLE, sequence_number)); | 168 task, |
| 169 base::TimeTicks(), |
| 170 sequence_number, |
| 171 task_type != TaskType::NON_NESTABLE); |
373 return true; | 172 return true; |
374 } | 173 } |
375 | 174 |
376 bool TaskQueueImpl::PostDelayedTaskImpl( | 175 bool TaskQueueImpl::PostDelayedTaskImpl( |
377 const tracked_objects::Location& from_here, | 176 const tracked_objects::Location& from_here, |
378 const base::Closure& task, | 177 const base::Closure& task, |
379 base::TimeDelta delay, | 178 base::TimeDelta delay, |
380 TaskType task_type) { | 179 TaskType task_type) { |
381 DCHECK_GT(delay, base::TimeDelta()); | 180 DCHECK_GT(delay, base::TimeDelta()); |
382 if (base::PlatformThread::CurrentId() == thread_id_) { | 181 if (base::PlatformThread::CurrentId() == thread_id_) { |
(...skipping 25 matching lines...) Expand all Loading... |
408 base::TimeTicks time_domain_now = any_thread().time_domain->Now(); | 207 base::TimeTicks time_domain_now = any_thread().time_domain->Now(); |
409 base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; | 208 base::TimeTicks time_domain_delayed_run_time = time_domain_now + delay; |
410 PushOntoDelayedIncomingQueueLocked( | 209 PushOntoDelayedIncomingQueueLocked( |
411 Task(from_here, task, time_domain_delayed_run_time, sequence_number, | 210 Task(from_here, task, time_domain_delayed_run_time, sequence_number, |
412 task_type != TaskType::NON_NESTABLE)); | 211 task_type != TaskType::NON_NESTABLE)); |
413 } | 212 } |
414 return true; | 213 return true; |
415 } | 214 } |
416 | 215 |
417 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( | 216 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread( |
418 Task pending_task, | 217 Task pending_task, base::TimeTicks now) { |
419 base::TimeTicks now) { | |
420 main_thread_only().task_queue_manager->DidQueueTask(pending_task); | 218 main_thread_only().task_queue_manager->DidQueueTask(pending_task); |
421 | 219 |
422 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. | 220 // Schedule a later call to MoveReadyDelayedTasksToDelayedWorkQueue. |
423 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 221 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
424 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 222 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
425 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, | 223 main_thread_only().time_domain->ScheduleDelayedWork(this, delayed_run_time, |
426 now); | 224 now); |
427 TraceQueueSize(false); | 225 TraceQueueSize(false); |
428 } | 226 } |
429 | 227 |
430 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { | 228 void TaskQueueImpl::PushOntoDelayedIncomingQueueLocked(Task pending_task) { |
431 any_thread().task_queue_manager->DidQueueTask(pending_task); | 229 any_thread().task_queue_manager->DidQueueTask(pending_task); |
432 | 230 |
433 int thread_hop_task_sequence_number = | 231 int thread_hop_task_sequence_number = |
434 any_thread().task_queue_manager->GetNextSequenceNumber(); | 232 any_thread().task_queue_manager->GetNextSequenceNumber(); |
435 PushOntoImmediateIncomingQueueLocked( | 233 PushOntoImmediateIncomingQueueLocked( |
436 Task(FROM_HERE, base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, | 234 FROM_HERE, |
437 base::Passed(&pending_task)), | 235 base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask, this, |
438 base::TimeTicks(), thread_hop_task_sequence_number, false, | 236 base::Passed(&pending_task)), |
439 thread_hop_task_sequence_number)); | 237 base::TimeTicks(), |
| 238 thread_hop_task_sequence_number, |
| 239 false); |
440 } | 240 } |
441 | 241 |
442 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked(Task pending_task) { | 242 void TaskQueueImpl::PushOntoImmediateIncomingQueueLocked( |
| 243 const tracked_objects::Location& posted_from, |
| 244 const base::Closure& task, |
| 245 base::TimeTicks desired_run_time, |
| 246 EnqueueOrder sequence_number, |
| 247 bool nestable) { |
443 if (any_thread().immediate_incoming_queue.empty()) | 248 if (any_thread().immediate_incoming_queue.empty()) |
444 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); | 249 any_thread().time_domain->RegisterAsUpdatableTaskQueue(this); |
445 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make | 250 // If the |immediate_incoming_queue| is empty we need a DoWork posted to make |
446 // it run. | 251 // it run. |
447 if (any_thread().immediate_incoming_queue.empty()) { | 252 if (any_thread().immediate_incoming_queue.empty()) { |
448 // There's no point posting a DoWork for a disabled queue, however we can | 253 // 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. | 254 // only tell if it's disabled from the main thread. |
450 if (base::PlatformThread::CurrentId() == thread_id_) { | 255 if (base::PlatformThread::CurrentId() == thread_id_) { |
451 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) | 256 if (main_thread_only().is_enabled && !BlockedByFenceLocked()) |
452 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 257 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
453 } else { | 258 } else { |
454 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); | 259 any_thread().task_queue_manager->MaybeScheduleImmediateWork(FROM_HERE); |
455 } | 260 } |
456 } | 261 } |
457 any_thread().task_queue_manager->DidQueueTask(pending_task); | 262 any_thread().immediate_incoming_queue.emplace( |
458 // We expect |pending_task| to be inserted at the end. Amoritized O(1). | 263 posted_from, task, desired_run_time, sequence_number, nestable, sequence_n
umber); |
459 any_thread().immediate_incoming_queue.insert( | 264 any_thread().task_queue_manager->DidQueueTask( any_thread().immediate_incoming
_queue.back()); |
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); | 265 TraceQueueSize(true); |
465 } | 266 } |
466 | 267 |
467 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { | 268 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) { |
468 DCHECK(main_thread_checker_.CalledOnValidThread()); | 269 DCHECK(main_thread_checker_.CalledOnValidThread()); |
469 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; | 270 base::TimeTicks delayed_run_time = pending_task.delayed_run_time; |
470 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); | 271 base::TimeTicks time_domain_now = main_thread_only().time_domain->Now(); |
471 // Make sure |delayed_run_time| isn't in the past. | 272 // Make sure |delayed_run_time| isn't in the past. |
472 if (delayed_run_time < time_domain_now) { | 273 if (delayed_run_time < time_domain_now) { |
473 delayed_run_time = time_domain_now; | 274 delayed_run_time = time_domain_now; |
474 pending_task.delayed_run_time = time_domain_now; | 275 pending_task.delayed_run_time = time_domain_now; |
475 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 276 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
476 LazyNow lazy_now(time_domain_now); | 277 LazyNow lazy_now(time_domain_now); |
477 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); | 278 MoveReadyDelayedTasksToDelayedWorkQueue(&lazy_now); |
478 } else { | 279 } else { |
479 main_thread_only().delayed_incoming_queue.insert(std::move(pending_task)); | 280 main_thread_only().delayed_incoming_queue.push(std::move(pending_task)); |
480 main_thread_only().time_domain->ScheduleDelayedWork( | 281 main_thread_only().time_domain->ScheduleDelayedWork( |
481 this, delayed_run_time, main_thread_only().time_domain->Now()); | 282 this, delayed_run_time, main_thread_only().time_domain->Now()); |
482 } | 283 } |
483 TraceQueueSize(false); | 284 TraceQueueSize(false); |
484 } | 285 } |
485 | 286 |
486 void TaskQueueImpl::SetQueueEnabled(bool enabled) { | 287 void TaskQueueImpl::SetQueueEnabled(bool enabled) { |
487 if (main_thread_only().is_enabled == enabled) | 288 if (main_thread_only().is_enabled == enabled) |
488 return; | 289 return; |
489 main_thread_only().is_enabled = enabled; | 290 main_thread_only().is_enabled = enabled; |
490 if (!main_thread_only().task_queue_manager) | 291 if (!main_thread_only().task_queue_manager) |
491 return; | 292 return; |
492 if (enabled) { | 293 if (enabled) { |
493 // Note it's the job of the selector to tell the TaskQueueManager if | 294 // Note it's the job of the selector to tell the TaskQueueManager if |
494 // a DoWork needs posting. | 295 // a DoWork needs posting. |
495 main_thread_only().task_queue_manager->selector_.EnableQueue(this); | 296 main_thread_only().task_queue_manager->selector_.EnableQueue(this); |
496 } else { | 297 } else { |
497 main_thread_only().task_queue_manager->selector_.DisableQueue(this); | 298 main_thread_only().task_queue_manager->selector_.DisableQueue(this); |
498 } | 299 } |
499 } | 300 } |
500 | 301 |
501 bool TaskQueueImpl::IsQueueEnabled() const { | 302 bool TaskQueueImpl::IsQueueEnabled() const { |
502 return main_thread_only().is_enabled; | 303 return main_thread_only().is_enabled; |
503 } | 304 } |
504 | 305 |
505 bool TaskQueueImpl::IsEmpty() const { | 306 bool TaskQueueImpl::IsEmpty() const { |
506 if (!main_thread_only().delayed_work_queue->Empty() || | 307 if (!main_thread_only().delayed_work_queue->Empty() || |
| 308 !main_thread_only().delayed_incoming_queue.empty() || |
507 !main_thread_only().immediate_work_queue->Empty()) { | 309 !main_thread_only().immediate_work_queue->Empty()) { |
508 return false; | 310 return false; |
509 } | 311 } |
510 | 312 |
511 base::AutoLock lock(any_thread_lock_); | 313 base::AutoLock lock(any_thread_lock_); |
512 return any_thread().immediate_incoming_queue.empty() && | 314 return any_thread().immediate_incoming_queue.empty(); |
513 main_thread_only().delayed_incoming_queue.empty(); | |
514 } | 315 } |
515 | 316 |
516 bool TaskQueueImpl::HasPendingImmediateWork() const { | 317 bool TaskQueueImpl::HasPendingImmediateWork() const { |
517 // Any work queue tasks count as immediate work. | 318 // Any work queue tasks count as immediate work. |
518 if (!main_thread_only().delayed_work_queue->Empty() || | 319 if (!main_thread_only().delayed_work_queue->Empty() || |
519 !main_thread_only().immediate_work_queue->Empty()) { | 320 !main_thread_only().immediate_work_queue->Empty()) { |
520 return true; | 321 return true; |
521 } | 322 } |
522 | 323 |
523 // Tasks on |delayed_incoming_queue| that could run now, count as | 324 // Tasks on |delayed_incoming_queue| that could run now, count as |
524 // immediate work. | 325 // immediate work. |
525 if (!main_thread_only().delayed_incoming_queue.empty() && | 326 if (!main_thread_only().delayed_incoming_queue.empty() && |
526 main_thread_only().delayed_incoming_queue.begin()->delayed_run_time <= | 327 main_thread_only().delayed_incoming_queue.top().delayed_run_time <= |
527 main_thread_only().time_domain->CreateLazyNow().Now()) { | 328 main_thread_only().time_domain->CreateLazyNow().Now()) { |
528 return true; | 329 return true; |
529 } | 330 } |
530 | 331 |
531 // Finally tasks on |immediate_incoming_queue| count as immediate work. | 332 // Finally tasks on |immediate_incoming_queue| count as immediate work. |
532 base::AutoLock lock(any_thread_lock_); | 333 base::AutoLock lock(any_thread_lock_); |
533 return !any_thread().immediate_incoming_queue.empty(); | 334 return !any_thread().immediate_incoming_queue.empty(); |
534 } | 335 } |
535 | 336 |
536 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { | 337 void TaskQueueImpl::MoveReadyDelayedTasksToDelayedWorkQueue(LazyNow* lazy_now) { |
537 // Enqueue all delayed tasks that should be running now. | 338 // Enqueue all delayed tasks that should be running now, skipping any that |
| 339 // have been canceled. |
538 while (!main_thread_only().delayed_incoming_queue.empty()) { | 340 while (!main_thread_only().delayed_incoming_queue.empty()) { |
539 DelayedRunTimeQueue::iterator next_task = | 341 // TODO(alexclarke): Use extract() when C++17 is allowed. |
540 main_thread_only().delayed_incoming_queue.begin(); | 342 Task& task = |
541 if (next_task->delayed_run_time > lazy_now->Now()) | 343 const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); |
| 344 if (task.task.IsCancelled()) { |
| 345 main_thread_only().delayed_incoming_queue.pop(); |
| 346 continue; |
| 347 } |
| 348 if (task.delayed_run_time > lazy_now->Now()) |
542 break; | 349 break; |
543 // TODO(alexclarke): Use extract() when C++17 is allowed. | |
544 Task& task = const_cast<Task&>(*next_task); | |
545 task.set_enqueue_order( | 350 task.set_enqueue_order( |
546 main_thread_only().task_queue_manager->GetNextSequenceNumber()); | 351 main_thread_only().task_queue_manager->GetNextSequenceNumber()); |
547 main_thread_only().delayed_work_queue->Push(std::move(task)); | 352 main_thread_only().delayed_work_queue->Push(std::move(task)); |
548 main_thread_only().delayed_incoming_queue.erase(next_task); | 353 main_thread_only().delayed_incoming_queue.pop(); |
549 } | 354 } |
550 } | 355 } |
551 | 356 |
552 void TaskQueueImpl::UpdateDelayedWorkQueue(LazyNow* lazy_now) { | 357 bool TaskQueueImpl::MaybeUpdateImmediateWorkQueues() { |
553 if (!main_thread_only().task_queue_manager) | 358 if (!main_thread_only().task_queue_manager) |
554 return; | 359 return false; |
555 MoveReadyDelayedTasksToDelayedWorkQueue(lazy_now); | |
556 TraceQueueSize(false); | |
557 } | |
558 | 360 |
559 void TaskQueueImpl::UpdateImmediateWorkQueue() { | 361 if (!main_thread_only().immediate_work_queue->Empty()) |
560 DCHECK(main_thread_only().immediate_work_queue->Empty()); | 362 return true; |
| 363 |
561 base::AutoLock lock(any_thread_lock_); | 364 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( | 365 main_thread_only().immediate_work_queue->SwapLocked( |
566 any_thread().immediate_incoming_queue); | 366 any_thread().immediate_incoming_queue); |
567 | 367 // |immediate_work_queue| is now empty so updates are no longer required. |
568 // |any_thread().immediate_incoming_queue| is now empty so | 368 return false; |
569 // TimeDomain::UpdateQueues no longer needs to consider this queue for | |
570 // reloading. | |
571 main_thread_only().time_domain->UnregisterAsUpdatableTaskQueue(this); | |
572 } | 369 } |
573 | 370 |
574 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { | 371 void TaskQueueImpl::TraceQueueSize(bool is_locked) const { |
575 bool is_tracing; | 372 bool is_tracing; |
576 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, | 373 TRACE_EVENT_CATEGORY_GROUP_ENABLED(disabled_by_default_tracing_category_, |
577 &is_tracing); | 374 &is_tracing); |
578 if (!is_tracing) | 375 if (!is_tracing) |
579 return; | 376 return; |
580 | 377 |
581 // It's only safe to access the work queues from the main thread. | 378 // 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", | 440 state->SetInteger("immediate_incoming_queue_size", |
644 any_thread().immediate_incoming_queue.size()); | 441 any_thread().immediate_incoming_queue.size()); |
645 state->SetInteger("delayed_incoming_queue_size", | 442 state->SetInteger("delayed_incoming_queue_size", |
646 main_thread_only().delayed_incoming_queue.size()); | 443 main_thread_only().delayed_incoming_queue.size()); |
647 state->SetInteger("immediate_work_queue_size", | 444 state->SetInteger("immediate_work_queue_size", |
648 main_thread_only().immediate_work_queue->Size()); | 445 main_thread_only().immediate_work_queue->Size()); |
649 state->SetInteger("delayed_work_queue_size", | 446 state->SetInteger("delayed_work_queue_size", |
650 main_thread_only().delayed_work_queue->Size()); | 447 main_thread_only().delayed_work_queue->Size()); |
651 if (!main_thread_only().delayed_incoming_queue.empty()) { | 448 if (!main_thread_only().delayed_incoming_queue.empty()) { |
652 base::TimeDelta delay_to_next_task = | 449 base::TimeDelta delay_to_next_task = |
653 (main_thread_only().delayed_incoming_queue.begin()->delayed_run_time - | 450 (main_thread_only().delayed_incoming_queue.top().delayed_run_time - |
654 main_thread_only().time_domain->CreateLazyNow().Now()); | 451 main_thread_only().time_domain->CreateLazyNow().Now()); |
655 state->SetDouble("delay_to_next_task_ms", | 452 state->SetDouble("delay_to_next_task_ms", |
656 delay_to_next_task.InMillisecondsF()); | 453 delay_to_next_task.InMillisecondsF()); |
657 } | 454 } |
658 if (verbose_tracing_enabled) { | 455 if (verbose_tracing_enabled) { |
659 state->BeginArray("immediate_incoming_queue"); | 456 state->BeginArray("immediate_incoming_queue"); |
660 QueueAsValueInto(any_thread().immediate_incoming_queue, state); | 457 QueueAsValueInto(any_thread().immediate_incoming_queue, state); |
661 state->EndArray(); | 458 state->EndArray(); |
662 state->BeginArray("delayed_work_queue"); | 459 state->BeginArray("delayed_work_queue"); |
663 main_thread_only().delayed_work_queue->AsValueInto(state); | 460 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 | 543 // Tasks posted after this point will have a strictly higher enqueue order |
747 // and will be blocked from running. | 544 // and will be blocked from running. |
748 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( | 545 bool task_unblocked = main_thread_only().immediate_work_queue->InsertFence( |
749 main_thread_only().current_fence); | 546 main_thread_only().current_fence); |
750 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( | 547 task_unblocked |= main_thread_only().delayed_work_queue->InsertFence( |
751 main_thread_only().current_fence); | 548 main_thread_only().current_fence); |
752 | 549 |
753 if (!task_unblocked && previous_fence) { | 550 if (!task_unblocked && previous_fence) { |
754 base::AutoLock lock(any_thread_lock_); | 551 base::AutoLock lock(any_thread_lock_); |
755 if (!any_thread().immediate_incoming_queue.empty() && | 552 if (!any_thread().immediate_incoming_queue.empty() && |
756 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 553 any_thread().immediate_incoming_queue.front().enqueue_order() > |
757 previous_fence && | 554 previous_fence && |
758 any_thread().immediate_incoming_queue.begin()->enqueue_order() < | 555 any_thread().immediate_incoming_queue.front().enqueue_order() < |
759 main_thread_only().current_fence) { | 556 main_thread_only().current_fence) { |
760 task_unblocked = true; | 557 task_unblocked = true; |
761 } | 558 } |
762 } | 559 } |
763 | 560 |
764 if (main_thread_only().is_enabled && task_unblocked) { | 561 if (main_thread_only().is_enabled && task_unblocked) { |
765 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 562 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
766 FROM_HERE); | 563 FROM_HERE); |
767 } | 564 } |
768 } | 565 } |
769 | 566 |
770 void TaskQueueImpl::RemoveFence() { | 567 void TaskQueueImpl::RemoveFence() { |
771 if (!main_thread_only().task_queue_manager) | 568 if (!main_thread_only().task_queue_manager) |
772 return; | 569 return; |
773 | 570 |
774 EnqueueOrder previous_fence = main_thread_only().current_fence; | 571 EnqueueOrder previous_fence = main_thread_only().current_fence; |
775 main_thread_only().current_fence = 0; | 572 main_thread_only().current_fence = 0; |
776 | 573 |
777 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); | 574 bool task_unblocked = main_thread_only().immediate_work_queue->RemoveFence(); |
778 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); | 575 task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence(); |
779 | 576 |
780 if (!task_unblocked && previous_fence) { | 577 if (!task_unblocked && previous_fence) { |
781 base::AutoLock lock(any_thread_lock_); | 578 base::AutoLock lock(any_thread_lock_); |
782 if (!any_thread().immediate_incoming_queue.empty() && | 579 if (!any_thread().immediate_incoming_queue.empty() && |
783 any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 580 any_thread().immediate_incoming_queue.front().enqueue_order() > |
784 previous_fence) { | 581 previous_fence) { |
785 task_unblocked = true; | 582 task_unblocked = true; |
786 } | 583 } |
787 } | 584 } |
788 | 585 |
789 if (main_thread_only().is_enabled && task_unblocked) { | 586 if (main_thread_only().is_enabled && task_unblocked) { |
790 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( | 587 main_thread_only().task_queue_manager->MaybeScheduleImmediateWork( |
791 FROM_HERE); | 588 FROM_HERE); |
792 } | 589 } |
793 } | 590 } |
794 | 591 |
795 bool TaskQueueImpl::BlockedByFence() const { | 592 bool TaskQueueImpl::BlockedByFence() const { |
796 if (!main_thread_only().current_fence) | 593 if (!main_thread_only().current_fence) |
797 return false; | 594 return false; |
798 | 595 |
799 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 596 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
800 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 597 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
801 return false; | 598 return false; |
802 } | 599 } |
803 | 600 |
804 base::AutoLock lock(any_thread_lock_); | 601 base::AutoLock lock(any_thread_lock_); |
805 if (any_thread().immediate_incoming_queue.empty()) | 602 if (any_thread().immediate_incoming_queue.empty()) |
806 return true; | 603 return true; |
807 | 604 |
808 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 605 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
809 main_thread_only().current_fence; | 606 main_thread_only().current_fence; |
810 } | 607 } |
811 | 608 |
812 bool TaskQueueImpl::BlockedByFenceLocked() const { | 609 bool TaskQueueImpl::BlockedByFenceLocked() const { |
813 if (!main_thread_only().current_fence) | 610 if (!main_thread_only().current_fence) |
814 return false; | 611 return false; |
815 | 612 |
816 if (!main_thread_only().immediate_work_queue->BlockedByFence() || | 613 if (!main_thread_only().immediate_work_queue->BlockedByFence() || |
817 !main_thread_only().delayed_work_queue->BlockedByFence()) { | 614 !main_thread_only().delayed_work_queue->BlockedByFence()) { |
818 return false; | 615 return false; |
819 } | 616 } |
820 | 617 |
821 if (any_thread().immediate_incoming_queue.empty()) | 618 if (any_thread().immediate_incoming_queue.empty()) |
822 return true; | 619 return true; |
823 | 620 |
824 return any_thread().immediate_incoming_queue.begin()->enqueue_order() > | 621 return any_thread().immediate_incoming_queue.front().enqueue_order() > |
825 main_thread_only().current_fence; | 622 main_thread_only().current_fence; |
826 } | 623 } |
827 | 624 |
828 // static | 625 // static |
829 void TaskQueueImpl::QueueAsValueInto(const ComparatorQueue& queue, | 626 void TaskQueueImpl::QueueAsValueInto(const std::queue<Task>& queue, |
830 base::trace_event::TracedValue* state) { | 627 base::trace_event::TracedValue* state) { |
831 for (const Task& task : queue) { | 628 // Remove const to search |queue| in the destructive manner. Restore the |
832 TaskAsValueInto(task, state); | 629 // content from |visited| later. |
| 630 std::queue<Task>* mutable_queue = const_cast<std::queue<Task>*>(&queue); |
| 631 std::queue<Task> visited; |
| 632 while (!mutable_queue->empty()) { |
| 633 TaskAsValueInto(mutable_queue->front(), state); |
| 634 visited.push(std::move(mutable_queue->front())); |
| 635 mutable_queue->pop(); |
833 } | 636 } |
| 637 *mutable_queue = std::move(visited); |
834 } | 638 } |
835 | 639 |
836 // static | 640 // static |
837 void TaskQueueImpl::QueueAsValueInto(const DelayedRunTimeQueue& queue, | 641 void TaskQueueImpl::QueueAsValueInto(const std::priority_queue<Task>& queue, |
838 base::trace_event::TracedValue* state) { | 642 base::trace_event::TracedValue* state) { |
839 for (const Task& task : queue) { | 643 // Remove const to search |queue| in the destructive manner. Restore the |
840 TaskAsValueInto(task, state); | 644 // content from |visited| later. |
| 645 std::priority_queue<Task>* mutable_queue = |
| 646 const_cast<std::priority_queue<Task>*>(&queue); |
| 647 std::priority_queue<Task> visited; |
| 648 while (!mutable_queue->empty()) { |
| 649 TaskAsValueInto(mutable_queue->top(), state); |
| 650 visited.push(std::move(const_cast<Task&>(mutable_queue->top()))); |
| 651 mutable_queue->pop(); |
841 } | 652 } |
| 653 *mutable_queue = std::move(visited); |
842 } | 654 } |
843 | 655 |
844 // static | 656 // static |
845 void TaskQueueImpl::TaskAsValueInto(const Task& task, | 657 void TaskQueueImpl::TaskAsValueInto(const Task& task, |
846 base::trace_event::TracedValue* state) { | 658 base::trace_event::TracedValue* state) { |
847 state->BeginDictionary(); | 659 state->BeginDictionary(); |
848 state->SetString("posted_from", task.posted_from.ToString()); | 660 state->SetString("posted_from", task.posted_from.ToString()); |
849 #ifndef NDEBUG | 661 #ifndef NDEBUG |
850 if (task.enqueue_order_set()) | 662 if (task.enqueue_order_set()) |
851 state->SetInteger("enqueue_order", task.enqueue_order()); | 663 state->SetInteger("enqueue_order", task.enqueue_order()); |
852 #else | 664 #else |
853 state->SetInteger("enqueue_order", task.enqueue_order()); | 665 state->SetInteger("enqueue_order", task.enqueue_order()); |
854 #endif | 666 #endif |
855 state->SetInteger("sequence_num", task.sequence_num); | 667 state->SetInteger("sequence_num", task.sequence_num); |
856 state->SetBoolean("nestable", task.nestable); | 668 state->SetBoolean("nestable", task.nestable); |
857 state->SetBoolean("is_high_res", task.is_high_res); | 669 state->SetBoolean("is_high_res", task.is_high_res); |
| 670 state->SetBoolean("is_cancelled", task.task.IsCancelled()); |
858 state->SetDouble( | 671 state->SetDouble( |
859 "delayed_run_time", | 672 "delayed_run_time", |
860 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); | 673 (task.delayed_run_time - base::TimeTicks()).InMicroseconds() / 1000.0L); |
861 state->EndDictionary(); | 674 state->EndDictionary(); |
862 } | 675 } |
863 | 676 |
864 } // namespace internal | 677 } // namespace internal |
865 } // namespace scheduler | 678 } // namespace scheduler |
866 } // namespace blink | 679 } // namespace blink |
OLD | NEW |