Chromium Code Reviews| Index: third_party/WebKit/Source/platform/scheduler/base/work_queue.cc |
| diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc b/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc |
| index 7274802b8b202c321eb01879d80d1e3d7a8a4148..0e6e980238d78228d81d2950474dd6e8e9c18a7d 100644 |
| --- a/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc |
| +++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue.cc |
| @@ -17,7 +17,9 @@ WorkQueue::WorkQueue(TaskQueueImpl* task_queue, |
| work_queue_sets_(nullptr), |
| task_queue_(task_queue), |
| work_queue_set_index_(0), |
| - name_(name) {} |
| + name_(name), |
| + fence_(0), |
| + fence_hit_(false) {} |
| void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { |
| for (const TaskQueueImpl::Task& task : work_queue_) { |
| @@ -36,8 +38,14 @@ const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const { |
| return &*work_queue_.begin(); |
| } |
| -bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { |
| +const TaskQueueImpl::Task* WorkQueue::GetBackTask() const { |
| if (work_queue_.empty()) |
| + return nullptr; |
| + return &*work_queue_.rbegin(); |
| +} |
| + |
| +bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { |
| + if (work_queue_.empty() || fence_hit_) |
| return false; |
| // Quick sanity check. |
| DCHECK_LE(work_queue_.begin()->enqueue_order(), |
| @@ -64,7 +72,7 @@ void WorkQueue::Push(TaskQueueImpl::Task task) { |
| "] rbegin() [" << work_queue_.rbegin()->delayed_run_time << ", " |
| << work_queue_.rbegin()->sequence_num << "]"; |
| - if (was_empty && work_queue_sets_) { |
| + if (was_empty && work_queue_sets_ && !fence_hit_) { |
| work_queue_sets_->OnPushQueue(this); |
| } |
| } |
| @@ -80,7 +88,8 @@ bool WorkQueue::CancelTask(const TaskQueueImpl::Task& key) { |
| // We can't guarantee this WorkQueue is the lowest value in the WorkQueueSet |
| // so we need to use OnQueueHeadChanged instead of OnPopQueue for |
| // correctness. |
| - work_queue_sets_->OnQueueHeadChanged(this, erased_task_enqueue_order); |
| + if (!fence_hit_) |
| + work_queue_sets_->OnQueueHeadChanged(this, erased_task_enqueue_order); |
| } else { |
| work_queue_.erase(it); |
| } |
| @@ -101,9 +110,8 @@ void WorkQueue::PopTaskForTest() { |
| void WorkQueue::SwapLocked(TaskQueueImpl::ComparatorQueue& incoming_queue) { |
| DCHECK(work_queue_.empty()); |
| std::swap(work_queue_, incoming_queue); |
| - if (!work_queue_.empty() && work_queue_sets_) |
| + if (!work_queue_.empty() && work_queue_sets_ && !fence_hit_) |
| work_queue_sets_->OnPushQueue(this); |
| - task_queue_->TraceQueueSize(true); |
|
Sami
2016/08/26 14:37:02
Did you mean to remove this?
alex clarke (OOO till 29th)
2016/08/26 16:33:14
Yes it's not useful to call it here since Swap doe
|
| } |
| TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { |
| @@ -113,6 +121,10 @@ TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { |
| TaskQueueImpl::Task pending_task = |
| std::move(const_cast<TaskQueueImpl::Task&>(*it)); |
| work_queue_.erase(it); |
| + // If we hit the fence, pretend to WorkQueueSets that we're empty until the |
| + // fence is removed. |
| + if (fence_ && pending_task.enqueue_order() >= fence_) |
| + fence_hit_ = true; |
| work_queue_sets_->OnPopQueue(this); |
| task_queue_->TraceQueueSize(false); |
| return pending_task; |
| @@ -126,6 +138,34 @@ void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { |
| work_queue_set_index_ = work_queue_set_index; |
| } |
| +bool WorkQueue::InsertFence(EnqueueOrder fence) { |
| + bool task_unblocked = false; |
| + if (fence) { |
| + DCHECK_GE(fence, fence_); |
| + if (fence > fence_) |
| + task_unblocked = RemoveFence(); |
| + } else { |
| + DCHECK(work_queue_.empty()); |
| + // Until the fence is removed we should pretend to remain empty even after a |
| + // push or a swap. |
| + fence_hit_ = true; |
| + } |
| + |
| + fence_ = fence; |
| + return task_unblocked; |
| +} |
| + |
| +bool WorkQueue::RemoveFence() { |
| + fence_ = 0; |
| + bool fence_was_hit = fence_hit_; |
| + fence_hit_ = false; |
| + if (work_queue_sets_ && fence_was_hit && !work_queue_.empty()) { |
| + work_queue_sets_->OnPushQueue(this); |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const { |
| DCHECK(!work_queue_.empty()); |
| DCHECK(!other_queue->work_queue_.empty()); |