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..be7f403174cd70943a8fc9db29cc8542536d06b9 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,8 @@ WorkQueue::WorkQueue(TaskQueueImpl* task_queue, |
work_queue_sets_(nullptr), |
task_queue_(task_queue), |
work_queue_set_index_(0), |
- name_(name) {} |
+ name_(name), |
+ fence_(0) {} |
void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { |
for (const TaskQueueImpl::Task& task : work_queue_) { |
@@ -36,8 +37,24 @@ 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::BlockedByFence() const { |
+ if (!fence_) |
+ return false; |
+ |
+ // If the queue is empty then any future tasks will have a higher enqueue |
+ // order and will be blocked. The queue is also blocked if the head is past |
+ // the fence. |
+ return work_queue_.empty() || work_queue_.begin()->enqueue_order() > fence_; |
+} |
+ |
+bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { |
+ if (work_queue_.empty() || BlockedByFence()) |
return false; |
// Quick sanity check. |
DCHECK_LE(work_queue_.begin()->enqueue_order(), |
@@ -64,9 +81,12 @@ 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) |
+ return; |
+ |
+ // If we hit the fence, pretend to WorkQueueSets that we're empty. |
+ if (work_queue_sets_ && !BlockedByFence()) |
work_queue_sets_->OnPushQueue(this); |
- } |
} |
bool WorkQueue::CancelTask(const TaskQueueImpl::Task& key) { |
@@ -80,7 +100,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 (!BlockedByFence()) |
+ work_queue_sets_->OnQueueHeadChanged(this, erased_task_enqueue_order); |
} else { |
work_queue_.erase(it); |
} |
@@ -101,9 +122,11 @@ 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()) |
+ return; |
+ // If we hit the fence, pretend to WorkQueueSets that we're empty. |
+ if (work_queue_sets_ && !BlockedByFence()) |
work_queue_sets_->OnPushQueue(this); |
- task_queue_->TraceQueueSize(true); |
} |
TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { |
@@ -126,6 +149,30 @@ void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { |
work_queue_set_index_ = work_queue_set_index; |
} |
+bool WorkQueue::InsertFence(EnqueueOrder fence) { |
+ DCHECK_NE(fence, 0u); |
+ DCHECK_GE(fence, fence_); |
+ bool was_blocked_by_fence = BlockedByFence(); |
+ fence_ = fence; |
+ // Moving the fence forward may unblock some tasks. |
+ if (work_queue_sets_ && !work_queue_.empty() && was_blocked_by_fence && |
+ !BlockedByFence()) { |
+ work_queue_sets_->OnPushQueue(this); |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+bool WorkQueue::RemoveFence() { |
+ bool was_blocked_by_fence = BlockedByFence(); |
+ fence_ = 0; |
+ if (work_queue_sets_ && !work_queue_.empty() && was_blocked_by_fence) { |
+ 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()); |