Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: components/scheduler/base/task_queue_selector.cc

Issue 1685093002: Fix bug with TaskQueueSelector and blocked queues (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix UAF Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "components/scheduler/base/task_queue_selector.h" 5 #include "components/scheduler/base/task_queue_selector.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/trace_event/trace_event_argument.h" 8 #include "base/trace_event/trace_event_argument.h"
9 #include "components/scheduler/base/task_queue_impl.h" 9 #include "components/scheduler/base/task_queue_impl.h"
10 #include "components/scheduler/base/work_queue.h" 10 #include "components/scheduler/base/work_queue.h"
11 11
12 namespace scheduler { 12 namespace scheduler {
13 namespace internal { 13 namespace internal {
14 14
15 TaskQueueSelector::TaskQueueSelector() 15 TaskQueueSelector::TaskQueueSelector()
16 : enabled_selector_(this), 16 : enabled_selector_(this, "enabled"),
17 blocked_selector_(this), 17 blocked_selector_(this, "blocked"),
18 immediate_starvation_count_(0), 18 immediate_starvation_count_(0),
19 high_priority_starvation_count_(0), 19 high_priority_starvation_count_(0),
20 num_blocked_queues_to_report_(0), 20 num_blocked_queues_to_report_(0),
21 task_queue_selector_observer_(nullptr) {} 21 task_queue_selector_observer_(nullptr) {}
22 22
23 TaskQueueSelector::~TaskQueueSelector() {} 23 TaskQueueSelector::~TaskQueueSelector() {}
24 24
25 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) { 25 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
26 DCHECK(main_thread_checker_.CalledOnValidThread()); 26 DCHECK(main_thread_checker_.CalledOnValidThread());
27 DCHECK(queue->IsQueueEnabled()); 27 DCHECK(queue->IsQueueEnabled());
28 SetQueuePriority(queue, TaskQueue::NORMAL_PRIORITY); 28 enabled_selector_.AddQueue(queue, TaskQueue::NORMAL_PRIORITY);
29 } 29 }
30 30
31 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) { 31 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) {
32 DCHECK(main_thread_checker_.CalledOnValidThread()); 32 DCHECK(main_thread_checker_.CalledOnValidThread());
33 if (queue->IsQueueEnabled()) { 33 if (queue->IsQueueEnabled()) {
34 enabled_selector_.RemoveQueue(queue); 34 enabled_selector_.RemoveQueue(queue);
35 // The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
36 // chromeos bots without it :(
37 #if DCHECK_IS_ON()
38 DCHECK(!blocked_selector_.CheckContainsQueueForTest(queue));
39 #endif
35 } else if (queue->should_report_when_execution_blocked()) { 40 } else if (queue->should_report_when_execution_blocked()) {
36 DCHECK_GT(num_blocked_queues_to_report_, 0u); 41 DCHECK_GT(num_blocked_queues_to_report_, 0u);
37 num_blocked_queues_to_report_--; 42 num_blocked_queues_to_report_--;
38 blocked_selector_.RemoveQueue(queue); 43 blocked_selector_.RemoveQueue(queue);
44 #if DCHECK_IS_ON()
45 DCHECK(!enabled_selector_.CheckContainsQueueForTest(queue));
46 #endif
39 } 47 }
40 } 48 }
41 49
42 void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) { 50 void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) {
43 DCHECK(main_thread_checker_.CalledOnValidThread()); 51 DCHECK(main_thread_checker_.CalledOnValidThread());
44 DCHECK(queue->IsQueueEnabled()); 52 DCHECK(queue->IsQueueEnabled());
45 if (queue->should_report_when_execution_blocked()) { 53 if (queue->should_report_when_execution_blocked()) {
46 DCHECK_GT(num_blocked_queues_to_report_, 0u); 54 DCHECK_GT(num_blocked_queues_to_report_, 0u);
47 num_blocked_queues_to_report_--; 55 num_blocked_queues_to_report_--;
56 blocked_selector_.RemoveQueue(queue);
48 } 57 }
49 blocked_selector_.RemoveQueue(queue); 58 enabled_selector_.AddQueue(queue, queue->GetQueuePriority());
50 enabled_selector_.AssignQueueToSet(queue, queue->GetQueuePriority());
51 if (task_queue_selector_observer_) 59 if (task_queue_selector_observer_)
52 task_queue_selector_observer_->OnTaskQueueEnabled(queue); 60 task_queue_selector_observer_->OnTaskQueueEnabled(queue);
53 } 61 }
54 62
55 void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) { 63 void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) {
56 DCHECK(main_thread_checker_.CalledOnValidThread()); 64 DCHECK(main_thread_checker_.CalledOnValidThread());
57 DCHECK(!queue->IsQueueEnabled()); 65 DCHECK(!queue->IsQueueEnabled());
58 enabled_selector_.RemoveQueue(queue); 66 enabled_selector_.RemoveQueue(queue);
59 blocked_selector_.AssignQueueToSet(queue, queue->GetQueuePriority()); 67 if (queue->should_report_when_execution_blocked()) {
60 if (queue->should_report_when_execution_blocked()) 68 blocked_selector_.AddQueue(queue, queue->GetQueuePriority());
61 num_blocked_queues_to_report_++; 69 num_blocked_queues_to_report_++;
70 }
62 } 71 }
63 72
64 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue, 73 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue,
65 TaskQueue::QueuePriority priority) { 74 TaskQueue::QueuePriority priority) {
66 DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT); 75 DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT);
67 DCHECK(main_thread_checker_.CalledOnValidThread()); 76 DCHECK(main_thread_checker_.CalledOnValidThread());
68 if (queue->IsQueueEnabled()) { 77 if (queue->IsQueueEnabled()) {
69 enabled_selector_.AssignQueueToSet(queue, priority); 78 enabled_selector_.ChangeSetIndex(queue, priority);
79 } else if (queue->should_report_when_execution_blocked()) {
80 blocked_selector_.ChangeSetIndex(queue, priority);
70 } else { 81 } else {
71 blocked_selector_.AssignQueueToSet(queue, priority); 82 // Normally blocked_selector_.ChangeSetIndex would assign the queue's
83 // priority, however if |queue->should_report_when_execution_blocked()| is
84 // false then the disabled queue is not in any set so we need to do it here.
85 queue->delayed_work_queue()->AssignSetIndex(priority);
86 queue->immediate_work_queue()->AssignSetIndex(priority);
72 } 87 }
73 DCHECK_EQ(priority, queue->GetQueuePriority()); 88 DCHECK_EQ(priority, queue->GetQueuePriority());
74 } 89 }
75 90
76 TaskQueue::QueuePriority TaskQueueSelector::NextPriority( 91 TaskQueue::QueuePriority TaskQueueSelector::NextPriority(
77 TaskQueue::QueuePriority priority) { 92 TaskQueue::QueuePriority priority) {
78 DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT); 93 DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT);
79 return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1); 94 return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1);
80 } 95 }
81 96
82 TaskQueueSelector::PrioritizingSelector::PrioritizingSelector( 97 TaskQueueSelector::PrioritizingSelector::PrioritizingSelector(
83 TaskQueueSelector* task_queue_selector) 98 TaskQueueSelector* task_queue_selector,
99 const char* name)
84 : task_queue_selector_(task_queue_selector), 100 : task_queue_selector_(task_queue_selector),
85 delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT), 101 delayed_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name),
86 immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT) {} 102 immediate_work_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT, name) {}
87 103
88 void TaskQueueSelector::PrioritizingSelector::AssignQueueToSet( 104 void TaskQueueSelector::PrioritizingSelector::AddQueue(
89 internal::TaskQueueImpl* queue, 105 internal::TaskQueueImpl* queue,
90 TaskQueue::QueuePriority priority) { 106 TaskQueue::QueuePriority priority) {
91 delayed_work_queue_sets_.AssignQueueToSet(queue->delayed_work_queue(), 107 #if DCHECK_IS_ON()
108 DCHECK(!CheckContainsQueueForTest(queue));
109 #endif
110 delayed_work_queue_sets_.AddQueue(queue->delayed_work_queue(), priority);
111 immediate_work_queue_sets_.AddQueue(queue->immediate_work_queue(), priority);
112 #if DCHECK_IS_ON()
113 DCHECK(CheckContainsQueueForTest(queue));
114 #endif
115 }
116
117 void TaskQueueSelector::PrioritizingSelector::ChangeSetIndex(
118 internal::TaskQueueImpl* queue,
119 TaskQueue::QueuePriority priority) {
120 #if DCHECK_IS_ON()
121 DCHECK(CheckContainsQueueForTest(queue));
122 #endif
123 delayed_work_queue_sets_.ChangeSetIndex(queue->delayed_work_queue(),
124 priority);
125 immediate_work_queue_sets_.ChangeSetIndex(queue->immediate_work_queue(),
92 priority); 126 priority);
93 immediate_work_queue_sets_.AssignQueueToSet(queue->immediate_work_queue(),
94 priority);
95 // The #if DCHECK_IS_ON() shouldn't be necessary but this doesn't compile on
96 // chromeos bots without it :(
97 #if DCHECK_IS_ON() 127 #if DCHECK_IS_ON()
98 DCHECK_EQ(queue->delayed_work_queue()->Empty(), 128 DCHECK(CheckContainsQueueForTest(queue));
99 !delayed_work_queue_sets_.ContainsWorkQueueForTest(
100 queue->delayed_work_queue()));
101 DCHECK_EQ(queue->immediate_work_queue()->Empty(),
102 !immediate_work_queue_sets_.ContainsWorkQueueForTest(
103 queue->immediate_work_queue()));
104 #endif 129 #endif
105 } 130 }
106 131
107 void TaskQueueSelector::PrioritizingSelector::RemoveQueue( 132 void TaskQueueSelector::PrioritizingSelector::RemoveQueue(
108 internal::TaskQueueImpl* queue) { 133 internal::TaskQueueImpl* queue) {
109 #if DCHECK_IS_ON() 134 #if DCHECK_IS_ON()
110 DCHECK_EQ(queue->delayed_work_queue()->Empty(), 135 DCHECK(CheckContainsQueueForTest(queue));
111 !delayed_work_queue_sets_.ContainsWorkQueueForTest(
112 queue->delayed_work_queue()))
113 << " Did you try to RemoveQueue twice? Thats not supported!";
114 DCHECK_EQ(queue->immediate_work_queue()->Empty(),
115 !immediate_work_queue_sets_.ContainsWorkQueueForTest(
116 queue->immediate_work_queue()))
117 << " Did you try to RemoveQueue twice? Thats not supported!";
118 #endif 136 #endif
119 delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue()); 137 delayed_work_queue_sets_.RemoveQueue(queue->delayed_work_queue());
120 immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue()); 138 immediate_work_queue_sets_.RemoveQueue(queue->immediate_work_queue());
121 139
122 #if DCHECK_IS_ON() 140 #if DCHECK_IS_ON()
123 DCHECK(!delayed_work_queue_sets_.ContainsWorkQueueForTest( 141 DCHECK(!CheckContainsQueueForTest(queue));
124 queue->delayed_work_queue()));
125 DCHECK(!immediate_work_queue_sets_.ContainsWorkQueueForTest(
126 queue->delayed_work_queue()));
127 #endif 142 #endif
128 } 143 }
129 144
130 bool TaskQueueSelector::PrioritizingSelector:: 145 bool TaskQueueSelector::PrioritizingSelector::
131 ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority, 146 ChooseOldestImmediateTaskWithPriority(TaskQueue::QueuePriority priority,
132 WorkQueue** out_work_queue) const { 147 WorkQueue** out_work_queue) const {
133 return immediate_work_queue_sets_.GetOldestQueueInSet(priority, 148 return immediate_work_queue_sets_.GetOldestQueueInSet(priority,
134 out_work_queue); 149 out_work_queue);
135 } 150 }
136 151
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY; 228 for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY;
214 priority < max_priority; priority = NextPriority(priority)) { 229 priority < max_priority; priority = NextPriority(priority)) {
215 if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate, 230 if (ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate,
216 out_work_queue)) { 231 out_work_queue)) {
217 return true; 232 return true;
218 } 233 }
219 } 234 }
220 return false; 235 return false;
221 } 236 }
222 237
238 #if DCHECK_IS_ON() || !defined(NDEBUG)
239 bool
240 TaskQueueSelector::PrioritizingSelector::CheckContainsQueueForTest(
241 const internal::TaskQueueImpl* queue) const {
242 bool contains_delayed_work_queue =
243 delayed_work_queue_sets_.ContainsWorkQueueForTest(
244 queue->delayed_work_queue());
245
246 bool contains_immediate_work_queue =
247 immediate_work_queue_sets_.ContainsWorkQueueForTest(
248 queue->immediate_work_queue());
249
250 DCHECK_EQ(contains_delayed_work_queue, contains_immediate_work_queue);
251 return contains_delayed_work_queue;
252 }
253 #endif
254
223 bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) { 255 bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) {
224 DCHECK(main_thread_checker_.CalledOnValidThread()); 256 DCHECK(main_thread_checker_.CalledOnValidThread());
225 bool chose_delayed_over_immediate = false; 257 bool chose_delayed_over_immediate = false;
226 bool found_queue = enabled_selector_.SelectWorkQueueToService( 258 bool found_queue = enabled_selector_.SelectWorkQueueToService(
227 TaskQueue::QUEUE_PRIORITY_COUNT, out_work_queue, 259 TaskQueue::QUEUE_PRIORITY_COUNT, out_work_queue,
228 &chose_delayed_over_immediate); 260 &chose_delayed_over_immediate);
229 if (!found_queue) { 261 if (!found_queue) {
230 TrySelectingBlockedQueue(); 262 TrySelectingBlockedQueue();
231 return false; 263 return false;
232 } 264 }
233 265
234 TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue); 266 TrySelectingBlockedQueueOverEnabledQueue(**out_work_queue);
235 DidSelectQueueWithPriority( 267 DidSelectQueueWithPriority(
236 (*out_work_queue)->task_queue()->GetQueuePriority(), 268 (*out_work_queue)->task_queue()->GetQueuePriority(),
237 chose_delayed_over_immediate); 269 chose_delayed_over_immediate);
238 return true; 270 return true;
239 } 271 }
240 272
241 void TaskQueueSelector::TrySelectingBlockedQueue() { 273 void TaskQueueSelector::TrySelectingBlockedQueue() {
274 DCHECK(main_thread_checker_.CalledOnValidThread());
242 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) 275 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
243 return; 276 return;
244 WorkQueue* chosen_blocked_queue; 277 WorkQueue* chosen_blocked_queue;
245 bool chose_delayed_over_immediate = false; 278 bool chose_delayed_over_immediate = false;
246 // There was nothing unblocked to run, see if we could have run a blocked 279 // There was nothing unblocked to run, see if we could have run a blocked
247 // task. 280 // task.
248 if (blocked_selector_.SelectWorkQueueToService( 281 if (blocked_selector_.SelectWorkQueueToService(
249 TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue, 282 TaskQueue::QUEUE_PRIORITY_COUNT, &chosen_blocked_queue,
250 &chose_delayed_over_immediate)) { 283 &chose_delayed_over_immediate)) {
251 task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue( 284 task_queue_selector_observer_->OnTriedToSelectBlockedWorkQueue(
252 chosen_blocked_queue); 285 chosen_blocked_queue);
253 } 286 }
254 } 287 }
255 288
256 void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue( 289 void TaskQueueSelector::TrySelectingBlockedQueueOverEnabledQueue(
257 const WorkQueue& chosen_enabled_queue) { 290 const WorkQueue& chosen_enabled_queue) {
291 DCHECK(main_thread_checker_.CalledOnValidThread());
258 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_) 292 if (!num_blocked_queues_to_report_ || !task_queue_selector_observer_)
259 return; 293 return;
260 294
261 TaskQueue::QueuePriority max_priority = 295 TaskQueue::QueuePriority max_priority =
262 NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority()); 296 NextPriority(chosen_enabled_queue.task_queue()->GetQueuePriority());
263 297
264 WorkQueue* chosen_blocked_queue; 298 WorkQueue* chosen_blocked_queue;
265 bool chose_delayed_over_immediate = false; 299 bool chose_delayed_over_immediate = false;
266 bool found_queue = blocked_selector_.SelectWorkQueueToService( 300 bool found_queue = blocked_selector_.SelectWorkQueueToService(
267 max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate); 301 max_priority, &chosen_blocked_queue, &chose_delayed_over_immediate);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 state->SetInteger("immediate_starvation_count", immediate_starvation_count_); 352 state->SetInteger("immediate_starvation_count", immediate_starvation_count_);
319 state->SetInteger("num_blocked_queues_to_report", 353 state->SetInteger("num_blocked_queues_to_report",
320 num_blocked_queues_to_report_); 354 num_blocked_queues_to_report_);
321 } 355 }
322 356
323 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) { 357 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) {
324 task_queue_selector_observer_ = observer; 358 task_queue_selector_observer_ = observer;
325 } 359 }
326 360
327 bool TaskQueueSelector::EnabledWorkQueuesEmpty() const { 361 bool TaskQueueSelector::EnabledWorkQueuesEmpty() const {
362 DCHECK(main_thread_checker_.CalledOnValidThread());
328 for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY; 363 for (TaskQueue::QueuePriority priority = TaskQueue::CONTROL_PRIORITY;
329 priority < TaskQueue::QUEUE_PRIORITY_COUNT; 364 priority < TaskQueue::QUEUE_PRIORITY_COUNT;
330 priority = NextPriority(priority)) { 365 priority = NextPriority(priority)) {
331 if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) || 366 if (!enabled_selector_.delayed_work_queue_sets()->IsSetEmpty(priority) ||
332 !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) { 367 !enabled_selector_.immediate_work_queue_sets()->IsSetEmpty(priority)) {
333 return false; 368 return false;
334 } 369 }
335 } 370 }
336 return true; 371 return true;
337 } 372 }
338 373
339 void TaskQueueSelector::SetImmediateStarvationCountForTest( 374 void TaskQueueSelector::SetImmediateStarvationCountForTest(
340 size_t immediate_starvation_count) { 375 size_t immediate_starvation_count) {
341 immediate_starvation_count_ = immediate_starvation_count; 376 immediate_starvation_count_ = immediate_starvation_count;
342 } 377 }
343 378
344 } // namespace internal 379 } // namespace internal
345 } // namespace scheduler 380 } // namespace scheduler
OLDNEW
« no previous file with comments | « components/scheduler/base/task_queue_selector.h ('k') | components/scheduler/base/task_queue_selector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698