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