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()); |