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/work_queue.h" | 5 #include "platform/scheduler/base/work_queue.h" |
6 | 6 |
7 #include "platform/scheduler/base/work_queue_sets.h" | 7 #include "platform/scheduler/base/work_queue_sets.h" |
8 | 8 |
9 namespace blink { | 9 namespace blink { |
10 namespace scheduler { | 10 namespace scheduler { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
13 WorkQueue::WorkQueue(TaskQueueImpl* task_queue, | 13 WorkQueue::WorkQueue(TaskQueueImpl* task_queue, |
14 const char* name, | 14 const char* name, |
15 TaskQueueImpl::Task::ComparatorFn comparator) | 15 TaskQueueImpl::Task::ComparatorFn comparator) |
16 : work_queue_(comparator), | 16 : work_queue_(comparator), |
17 work_queue_sets_(nullptr), | 17 work_queue_sets_(nullptr), |
18 task_queue_(task_queue), | 18 task_queue_(task_queue), |
19 work_queue_set_index_(0), | 19 work_queue_set_index_(0), |
20 name_(name) {} | 20 name_(name), |
21 fence_(0), | |
22 fence_hit_(false) {} | |
21 | 23 |
22 void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { | 24 void WorkQueue::AsValueInto(base::trace_event::TracedValue* state) const { |
23 for (const TaskQueueImpl::Task& task : work_queue_) { | 25 for (const TaskQueueImpl::Task& task : work_queue_) { |
24 TaskQueueImpl::TaskAsValueInto(task, state); | 26 TaskQueueImpl::TaskAsValueInto(task, state); |
25 } | 27 } |
26 } | 28 } |
27 | 29 |
28 WorkQueue::~WorkQueue() { | 30 WorkQueue::~WorkQueue() { |
29 DCHECK(!work_queue_sets_) << task_queue_->GetName() << " : " | 31 DCHECK(!work_queue_sets_) << task_queue_->GetName() << " : " |
30 << work_queue_sets_->name() << " : " << name_; | 32 << work_queue_sets_->name() << " : " << name_; |
31 } | 33 } |
32 | 34 |
33 const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const { | 35 const TaskQueueImpl::Task* WorkQueue::GetFrontTask() const { |
34 if (work_queue_.empty()) | 36 if (work_queue_.empty()) |
35 return nullptr; | 37 return nullptr; |
36 return &*work_queue_.begin(); | 38 return &*work_queue_.begin(); |
37 } | 39 } |
38 | 40 |
41 const TaskQueueImpl::Task* WorkQueue::GetBackTask() const { | |
42 if (work_queue_.empty()) | |
43 return nullptr; | |
44 return &*work_queue_.rbegin(); | |
45 } | |
46 | |
39 bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { | 47 bool WorkQueue::GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const { |
40 if (work_queue_.empty()) | 48 if (work_queue_.empty() || fence_hit_) |
41 return false; | 49 return false; |
42 // Quick sanity check. | 50 // Quick sanity check. |
43 DCHECK_LE(work_queue_.begin()->enqueue_order(), | 51 DCHECK_LE(work_queue_.begin()->enqueue_order(), |
44 work_queue_.rbegin()->enqueue_order()) | 52 work_queue_.rbegin()->enqueue_order()) |
45 << task_queue_->GetName() << " : " | 53 << task_queue_->GetName() << " : " |
46 << work_queue_sets_->name() << " : " << name_; | 54 << work_queue_sets_->name() << " : " << name_; |
47 *enqueue_order = work_queue_.begin()->enqueue_order(); | 55 *enqueue_order = work_queue_.begin()->enqueue_order(); |
48 return true; | 56 return true; |
49 } | 57 } |
50 | 58 |
51 void WorkQueue::Push(TaskQueueImpl::Task task) { | 59 void WorkQueue::Push(TaskQueueImpl::Task task) { |
52 bool was_empty = work_queue_.empty(); | 60 bool was_empty = work_queue_.empty(); |
53 #ifndef NDEBUG | 61 #ifndef NDEBUG |
54 DCHECK(task.enqueue_order_set()); | 62 DCHECK(task.enqueue_order_set()); |
55 #endif | 63 #endif |
56 | 64 |
57 // We expect |task| to be inserted at the end. Amoritized O(1). | 65 // We expect |task| to be inserted at the end. Amoritized O(1). |
58 work_queue_.insert(work_queue_.end(), std::move(task)); | 66 work_queue_.insert(work_queue_.end(), std::move(task)); |
59 DCHECK_EQ(task.enqueue_order(), work_queue_.rbegin()->enqueue_order()) | 67 DCHECK_EQ(task.enqueue_order(), work_queue_.rbegin()->enqueue_order()) |
60 << task_queue_->GetName() << " : " | 68 << task_queue_->GetName() << " : " |
61 << work_queue_sets_->name() << " : " << name_ | 69 << work_queue_sets_->name() << " : " << name_ |
62 << "task [scheduled_run_time_" << task.delayed_run_time << ", " | 70 << "task [scheduled_run_time_" << task.delayed_run_time << ", " |
63 << task.sequence_num << | 71 << task.sequence_num << |
64 "] rbegin() [" << work_queue_.rbegin()->delayed_run_time << ", " | 72 "] rbegin() [" << work_queue_.rbegin()->delayed_run_time << ", " |
65 << work_queue_.rbegin()->sequence_num << "]"; | 73 << work_queue_.rbegin()->sequence_num << "]"; |
66 | 74 |
67 if (was_empty && work_queue_sets_) { | 75 if (was_empty && work_queue_sets_ && !fence_hit_) { |
68 work_queue_sets_->OnPushQueue(this); | 76 work_queue_sets_->OnPushQueue(this); |
69 } | 77 } |
70 } | 78 } |
71 | 79 |
72 bool WorkQueue::CancelTask(const TaskQueueImpl::Task& key) { | 80 bool WorkQueue::CancelTask(const TaskQueueImpl::Task& key) { |
73 TaskQueueImpl::ComparatorQueue::iterator it = work_queue_.find(key); | 81 TaskQueueImpl::ComparatorQueue::iterator it = work_queue_.find(key); |
74 if (it == work_queue_.end()) | 82 if (it == work_queue_.end()) |
75 return false; | 83 return false; |
76 | 84 |
77 if (it == work_queue_.begin()) { | 85 if (it == work_queue_.begin()) { |
78 EnqueueOrder erased_task_enqueue_order = it->enqueue_order(); | 86 EnqueueOrder erased_task_enqueue_order = it->enqueue_order(); |
79 work_queue_.erase(it); | 87 work_queue_.erase(it); |
80 // We can't guarantee this WorkQueue is the lowest value in the WorkQueueSet | 88 // We can't guarantee this WorkQueue is the lowest value in the WorkQueueSet |
81 // so we need to use OnQueueHeadChanged instead of OnPopQueue for | 89 // so we need to use OnQueueHeadChanged instead of OnPopQueue for |
82 // correctness. | 90 // correctness. |
83 work_queue_sets_->OnQueueHeadChanged(this, erased_task_enqueue_order); | 91 if (!fence_hit_) |
92 work_queue_sets_->OnQueueHeadChanged(this, erased_task_enqueue_order); | |
84 } else { | 93 } else { |
85 work_queue_.erase(it); | 94 work_queue_.erase(it); |
86 } | 95 } |
87 task_queue_->TraceQueueSize(false); | 96 task_queue_->TraceQueueSize(false); |
88 return true; | 97 return true; |
89 } | 98 } |
90 | 99 |
91 bool WorkQueue::IsTaskPending(const TaskQueueImpl::Task& key) const { | 100 bool WorkQueue::IsTaskPending(const TaskQueueImpl::Task& key) const { |
92 return work_queue_.find(key) != work_queue_.end(); | 101 return work_queue_.find(key) != work_queue_.end(); |
93 } | 102 } |
94 | 103 |
95 void WorkQueue::PopTaskForTest() { | 104 void WorkQueue::PopTaskForTest() { |
96 if (work_queue_.empty()) | 105 if (work_queue_.empty()) |
97 return; | 106 return; |
98 work_queue_.erase(work_queue_.begin()); | 107 work_queue_.erase(work_queue_.begin()); |
99 } | 108 } |
100 | 109 |
101 void WorkQueue::SwapLocked(TaskQueueImpl::ComparatorQueue& incoming_queue) { | 110 void WorkQueue::SwapLocked(TaskQueueImpl::ComparatorQueue& incoming_queue) { |
102 DCHECK(work_queue_.empty()); | 111 DCHECK(work_queue_.empty()); |
103 std::swap(work_queue_, incoming_queue); | 112 std::swap(work_queue_, incoming_queue); |
104 if (!work_queue_.empty() && work_queue_sets_) | 113 if (!work_queue_.empty() && work_queue_sets_ && !fence_hit_) |
105 work_queue_sets_->OnPushQueue(this); | 114 work_queue_sets_->OnPushQueue(this); |
106 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
| |
107 } | 115 } |
108 | 116 |
109 TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { | 117 TaskQueueImpl::Task WorkQueue::TakeTaskFromWorkQueue() { |
110 DCHECK(work_queue_sets_); | 118 DCHECK(work_queue_sets_); |
111 DCHECK(!work_queue_.empty()); | 119 DCHECK(!work_queue_.empty()); |
112 TaskQueueImpl::ComparatorQueue::iterator it = work_queue_.begin(); | 120 TaskQueueImpl::ComparatorQueue::iterator it = work_queue_.begin(); |
113 TaskQueueImpl::Task pending_task = | 121 TaskQueueImpl::Task pending_task = |
114 std::move(const_cast<TaskQueueImpl::Task&>(*it)); | 122 std::move(const_cast<TaskQueueImpl::Task&>(*it)); |
115 work_queue_.erase(it); | 123 work_queue_.erase(it); |
124 // If we hit the fence, pretend to WorkQueueSets that we're empty until the | |
125 // fence is removed. | |
126 if (fence_ && pending_task.enqueue_order() >= fence_) | |
127 fence_hit_ = true; | |
116 work_queue_sets_->OnPopQueue(this); | 128 work_queue_sets_->OnPopQueue(this); |
117 task_queue_->TraceQueueSize(false); | 129 task_queue_->TraceQueueSize(false); |
118 return pending_task; | 130 return pending_task; |
119 } | 131 } |
120 | 132 |
121 void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) { | 133 void WorkQueue::AssignToWorkQueueSets(WorkQueueSets* work_queue_sets) { |
122 work_queue_sets_ = work_queue_sets; | 134 work_queue_sets_ = work_queue_sets; |
123 } | 135 } |
124 | 136 |
125 void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { | 137 void WorkQueue::AssignSetIndex(size_t work_queue_set_index) { |
126 work_queue_set_index_ = work_queue_set_index; | 138 work_queue_set_index_ = work_queue_set_index; |
127 } | 139 } |
128 | 140 |
141 bool WorkQueue::InsertFence(EnqueueOrder fence) { | |
142 bool task_unblocked = false; | |
143 if (fence) { | |
144 DCHECK_GE(fence, fence_); | |
145 if (fence > fence_) | |
146 task_unblocked = RemoveFence(); | |
147 } else { | |
148 DCHECK(work_queue_.empty()); | |
149 // Until the fence is removed we should pretend to remain empty even after a | |
150 // push or a swap. | |
151 fence_hit_ = true; | |
152 } | |
153 | |
154 fence_ = fence; | |
155 return task_unblocked; | |
156 } | |
157 | |
158 bool WorkQueue::RemoveFence() { | |
159 fence_ = 0; | |
160 bool fence_was_hit = fence_hit_; | |
161 fence_hit_ = false; | |
162 if (work_queue_sets_ && fence_was_hit && !work_queue_.empty()) { | |
163 work_queue_sets_->OnPushQueue(this); | |
164 return true; | |
165 } | |
166 return false; | |
167 } | |
168 | |
129 bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const { | 169 bool WorkQueue::ShouldRunBefore(const WorkQueue* other_queue) const { |
130 DCHECK(!work_queue_.empty()); | 170 DCHECK(!work_queue_.empty()); |
131 DCHECK(!other_queue->work_queue_.empty()); | 171 DCHECK(!other_queue->work_queue_.empty()); |
132 EnqueueOrder enqueue_order = 0; | 172 EnqueueOrder enqueue_order = 0; |
133 EnqueueOrder other_enqueue_order = 0; | 173 EnqueueOrder other_enqueue_order = 0; |
134 bool have_task = GetFrontTaskEnqueueOrder(&enqueue_order); | 174 bool have_task = GetFrontTaskEnqueueOrder(&enqueue_order); |
135 bool have_other_task = | 175 bool have_other_task = |
136 other_queue->GetFrontTaskEnqueueOrder(&other_enqueue_order); | 176 other_queue->GetFrontTaskEnqueueOrder(&other_enqueue_order); |
137 DCHECK(have_task); | 177 DCHECK(have_task); |
138 DCHECK(have_other_task); | 178 DCHECK(have_other_task); |
139 return enqueue_order < other_enqueue_order; | 179 return enqueue_order < other_enqueue_order; |
140 } | 180 } |
141 | 181 |
142 } // namespace internal | 182 } // namespace internal |
143 } // namespace scheduler | 183 } // namespace scheduler |
144 } // namespace blink | 184 } // namespace blink |
OLD | NEW |