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

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc

Issue 2487343004: Make sure scheduler shutdown prevents idle tasks from running (Closed)
Patch Set: Added a test which fails without the patch. Created 4 years, 1 month 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 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/child/idle_helper.h" 5 #include "platform/scheduler/child/idle_helper.h"
6 6
7 #include "base/time/time.h" 7 #include "base/time/time.h"
8 #include "base/trace_event/trace_event.h" 8 #include "base/trace_event/trace_event.h"
9 #include "base/trace_event/trace_event_argument.h" 9 #include "base/trace_event/trace_event_argument.h"
10 #include "platform/scheduler/base/real_time_domain.h" 10 #include "platform/scheduler/base/real_time_domain.h"
(...skipping 18 matching lines...) Expand all
29 helper_->NewTaskQueue(TaskQueue::Spec(TaskQueue::QueueType::IDLE))), 29 helper_->NewTaskQueue(TaskQueue::Spec(TaskQueue::QueueType::IDLE))),
30 state_(helper, 30 state_(helper,
31 delegate, 31 delegate,
32 tracing_category, 32 tracing_category,
33 disabled_by_default_tracing_category, 33 disabled_by_default_tracing_category,
34 idle_period_tracing_name), 34 idle_period_tracing_name),
35 required_quiescence_duration_before_long_idle_period_( 35 required_quiescence_duration_before_long_idle_period_(
36 required_quiescence_duration_before_long_idle_period), 36 required_quiescence_duration_before_long_idle_period),
37 disabled_by_default_tracing_category_( 37 disabled_by_default_tracing_category_(
38 disabled_by_default_tracing_category), 38 disabled_by_default_tracing_category),
39 is_shutdown_(false),
39 weak_factory_(this) { 40 weak_factory_(this) {
40 weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr(); 41 weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr();
41 enable_next_long_idle_period_closure_.Reset( 42 enable_next_long_idle_period_closure_.Reset(
42 base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_)); 43 base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_));
43 on_idle_task_posted_closure_.Reset(base::Bind( 44 on_idle_task_posted_closure_.Reset(base::Bind(
44 &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_)); 45 &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_));
45 46
46 idle_task_runner_ = make_scoped_refptr( 47 idle_task_runner_ = make_scoped_refptr(
47 new SingleThreadIdleTaskRunner(idle_queue_, this, tracing_category)); 48 new SingleThreadIdleTaskRunner(idle_queue_, this, tracing_category));
48 49
49 idle_queue_->SetQueueEnabled(false); 50 idle_queue_->SetQueueEnabled(false);
50 idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY); 51 idle_queue_->SetQueuePriority(TaskQueue::BEST_EFFORT_PRIORITY);
51 52
52 helper_->AddTaskObserver(this); 53 helper_->AddTaskObserver(this);
53 } 54 }
54 55
55 IdleHelper::~IdleHelper() { 56 IdleHelper::~IdleHelper() {
57 Shutdown();
58 }
59
60 void IdleHelper::Shutdown() {
61 if (is_shutdown_)
62 return;
63
64 EndIdlePeriod();
65 is_shutdown_ = true;
66 weak_factory_.InvalidateWeakPtrs();
67 // Belt & braces, might not be needed.
68 idle_queue_->SetQueueEnabled(false);
56 helper_->RemoveTaskObserver(this); 69 helper_->RemoveTaskObserver(this);
57 } 70 }
58 71
59 IdleHelper::Delegate::Delegate() {} 72 IdleHelper::Delegate::Delegate() {}
60 73
61 IdleHelper::Delegate::~Delegate() {} 74 IdleHelper::Delegate::~Delegate() {}
62 75
63 scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() { 76 scoped_refptr<SingleThreadIdleTaskRunner> IdleHelper::IdleTaskRunner() {
64 helper_->CheckOnValidThread(); 77 helper_->CheckOnValidThread();
65 return idle_task_runner_; 78 return idle_task_runner_;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // If we can't start the idle period yet then try again after wakeup. 115 // If we can't start the idle period yet then try again after wakeup.
103 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds( 116 *next_long_idle_period_delay_out = base::TimeDelta::FromMilliseconds(
104 kRetryEnableLongIdlePeriodDelayMillis); 117 kRetryEnableLongIdlePeriodDelayMillis);
105 return IdlePeriodState::NOT_IN_IDLE_PERIOD; 118 return IdlePeriodState::NOT_IN_IDLE_PERIOD;
106 } 119 }
107 } 120 }
108 121
109 bool IdleHelper::ShouldWaitForQuiescence() { 122 bool IdleHelper::ShouldWaitForQuiescence() {
110 helper_->CheckOnValidThread(); 123 helper_->CheckOnValidThread();
111 124
112 if (helper_->IsShutdown())
113 return false;
114
115 if (required_quiescence_duration_before_long_idle_period_ == 125 if (required_quiescence_duration_before_long_idle_period_ ==
116 base::TimeDelta()) { 126 base::TimeDelta()) {
117 return false; 127 return false;
118 } 128 }
119 129
120 bool system_is_quiescent = helper_->GetAndClearSystemIsQuiescentBit(); 130 bool system_is_quiescent = helper_->GetAndClearSystemIsQuiescentBit();
121 TRACE_EVENT1(disabled_by_default_tracing_category_, "ShouldWaitForQuiescence", 131 TRACE_EVENT1(disabled_by_default_tracing_category_, "ShouldWaitForQuiescence",
122 "system_is_quiescent", system_is_quiescent); 132 "system_is_quiescent", system_is_quiescent);
123 return !system_is_quiescent; 133 return !system_is_quiescent;
124 } 134 }
125 135
126 void IdleHelper::EnableLongIdlePeriod() { 136 void IdleHelper::EnableLongIdlePeriod() {
127 TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod"); 137 TRACE_EVENT0(disabled_by_default_tracing_category_, "EnableLongIdlePeriod");
128 helper_->CheckOnValidThread(); 138 helper_->CheckOnValidThread();
129 if (helper_->IsShutdown()) 139 if (is_shutdown_)
130 return; 140 return;
131 141
132 // End any previous idle period. 142 // End any previous idle period.
133 EndIdlePeriod(); 143 EndIdlePeriod();
134 144
135 if (ShouldWaitForQuiescence()) { 145 if (ShouldWaitForQuiescence()) {
136 helper_->ControlTaskRunner()->PostDelayedTask( 146 helper_->ControlTaskRunner()->PostDelayedTask(
137 FROM_HERE, enable_next_long_idle_period_closure_.callback(), 147 FROM_HERE, enable_next_long_idle_period_closure_.callback(),
138 required_quiescence_duration_before_long_idle_period_); 148 required_quiescence_duration_before_long_idle_period_);
139 delegate_->IsNotQuiescent(); 149 delegate_->IsNotQuiescent();
(...skipping 11 matching lines...) Expand all
151 // Otherwise wait for the next long idle period delay before trying again. 161 // Otherwise wait for the next long idle period delay before trying again.
152 helper_->ControlTaskRunner()->PostDelayedTask( 162 helper_->ControlTaskRunner()->PostDelayedTask(
153 FROM_HERE, enable_next_long_idle_period_closure_.callback(), 163 FROM_HERE, enable_next_long_idle_period_closure_.callback(),
154 next_long_idle_period_delay); 164 next_long_idle_period_delay);
155 } 165 }
156 } 166 }
157 167
158 void IdleHelper::StartIdlePeriod(IdlePeriodState new_state, 168 void IdleHelper::StartIdlePeriod(IdlePeriodState new_state,
159 base::TimeTicks now, 169 base::TimeTicks now,
160 base::TimeTicks idle_period_deadline) { 170 base::TimeTicks idle_period_deadline) {
171 DCHECK(!is_shutdown_);
161 DCHECK_GT(idle_period_deadline, now); 172 DCHECK_GT(idle_period_deadline, now);
162 helper_->CheckOnValidThread(); 173 helper_->CheckOnValidThread();
163 DCHECK(IsInIdlePeriod(new_state)); 174 DCHECK(IsInIdlePeriod(new_state));
164 175
165 base::TimeDelta idle_period_duration(idle_period_deadline - now); 176 base::TimeDelta idle_period_duration(idle_period_deadline - now);
166 if (idle_period_duration < 177 if (idle_period_duration <
167 base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) { 178 base::TimeDelta::FromMilliseconds(kMinimumIdlePeriodDurationMillis)) {
168 TRACE_EVENT1(disabled_by_default_tracing_category_, 179 TRACE_EVENT1(disabled_by_default_tracing_category_,
169 "NotStartingIdlePeriodBecauseDeadlineIsTooClose", 180 "NotStartingIdlePeriodBecauseDeadlineIsTooClose",
170 "idle_period_duration_ms", 181 "idle_period_duration_ms",
171 idle_period_duration.InMillisecondsF()); 182 idle_period_duration.InMillisecondsF());
172 return; 183 return;
173 } 184 }
174 185
175 TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod"); 186 TRACE_EVENT0(disabled_by_default_tracing_category_, "StartIdlePeriod");
176 idle_queue_->SetQueueEnabled(true); 187 idle_queue_->SetQueueEnabled(true);
177 // Use a fence to make sure any idle tasks posted after this point do not run 188 // Use a fence to make sure any idle tasks posted after this point do not run
178 // until the next idle period. 189 // until the next idle period.
179 idle_queue_->InsertFence(); 190 idle_queue_->InsertFence();
180 191
181 state_.UpdateState(new_state, idle_period_deadline, now); 192 state_.UpdateState(new_state, idle_period_deadline, now);
182 } 193 }
183 194
184 void IdleHelper::EndIdlePeriod() { 195 void IdleHelper::EndIdlePeriod() {
196 if (is_shutdown_)
197 return;
198
185 helper_->CheckOnValidThread(); 199 helper_->CheckOnValidThread();
186 TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod"); 200 TRACE_EVENT0(disabled_by_default_tracing_category_, "EndIdlePeriod");
187 201
188 enable_next_long_idle_period_closure_.Cancel(); 202 enable_next_long_idle_period_closure_.Cancel();
189 on_idle_task_posted_closure_.Cancel(); 203 on_idle_task_posted_closure_.Cancel();
190 204
191 // If we weren't already within an idle period then early-out. 205 // If we weren't already within an idle period then early-out.
192 if (!IsInIdlePeriod(state_.idle_period_state())) 206 if (!IsInIdlePeriod(state_.idle_period_state()))
193 return; 207 return;
194 208
195 idle_queue_->SetQueueEnabled(false); 209 idle_queue_->SetQueueEnabled(false);
196 state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(), 210 state_.UpdateState(IdlePeriodState::NOT_IN_IDLE_PERIOD, base::TimeTicks(),
197 base::TimeTicks()); 211 base::TimeTicks());
198 } 212 }
199 213
200 void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) {} 214 void IdleHelper::WillProcessTask(const base::PendingTask& pending_task) {
215 DCHECK(!is_shutdown_);
216 }
201 217
202 void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) { 218 void IdleHelper::DidProcessTask(const base::PendingTask& pending_task) {
203 helper_->CheckOnValidThread(); 219 helper_->CheckOnValidThread();
220 DCHECK(!is_shutdown_);
204 TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask"); 221 TRACE_EVENT0(disabled_by_default_tracing_category_, "DidProcessTask");
205 if (IsInIdlePeriod(state_.idle_period_state()) && 222 if (IsInIdlePeriod(state_.idle_period_state()) &&
206 state_.idle_period_state() != 223 state_.idle_period_state() !=
207 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED && 224 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED &&
208 helper_->scheduler_tqm_delegate()->NowTicks() >= 225 helper_->scheduler_tqm_delegate()->NowTicks() >=
209 state_.idle_period_deadline()) { 226 state_.idle_period_deadline()) {
210 // If the idle period deadline has now been reached, either end the idle 227 // If the idle period deadline has now been reached, either end the idle
211 // period or trigger a new long-idle period. 228 // period or trigger a new long-idle period.
212 if (IsInLongIdlePeriod(state_.idle_period_state())) { 229 if (IsInLongIdlePeriod(state_.idle_period_state())) {
213 EnableLongIdlePeriod(); 230 EnableLongIdlePeriod();
214 } else { 231 } else {
215 DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD == 232 DCHECK(IdlePeriodState::IN_SHORT_IDLE_PERIOD ==
216 state_.idle_period_state()); 233 state_.idle_period_state());
217 EndIdlePeriod(); 234 EndIdlePeriod();
218 } 235 }
219 } 236 }
220 } 237 }
221 238
222 void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() { 239 void IdleHelper::UpdateLongIdlePeriodStateAfterIdleTask() {
223 helper_->CheckOnValidThread(); 240 helper_->CheckOnValidThread();
241 DCHECK(!is_shutdown_);
224 DCHECK(IsInLongIdlePeriod(state_.idle_period_state())); 242 DCHECK(IsInLongIdlePeriod(state_.idle_period_state()));
225 TRACE_EVENT0(disabled_by_default_tracing_category_, 243 TRACE_EVENT0(disabled_by_default_tracing_category_,
226 "UpdateLongIdlePeriodStateAfterIdleTask"); 244 "UpdateLongIdlePeriodStateAfterIdleTask");
227 245
228 if (!idle_queue_->HasPendingImmediateWork()) { 246 if (!idle_queue_->HasPendingImmediateWork()) {
229 // If there are no more idle tasks then pause long idle period ticks until a 247 // If there are no more idle tasks then pause long idle period ticks until a
230 // new idle task is posted. 248 // new idle task is posted.
231 state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED, 249 state_.UpdateState(IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED,
232 state_.idle_period_deadline(), base::TimeTicks()); 250 state_.idle_period_deadline(), base::TimeTicks());
233 } else if (idle_queue_->BlockedByFence()) { 251 } else if (idle_queue_->BlockedByFence()) {
(...skipping 21 matching lines...) Expand all
255 } 273 }
256 } 274 }
257 275
258 base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const { 276 base::TimeTicks IdleHelper::CurrentIdleTaskDeadline() const {
259 helper_->CheckOnValidThread(); 277 helper_->CheckOnValidThread();
260 return state_.idle_period_deadline(); 278 return state_.idle_period_deadline();
261 } 279 }
262 280
263 void IdleHelper::OnIdleTaskPosted() { 281 void IdleHelper::OnIdleTaskPosted() {
264 TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted"); 282 TRACE_EVENT0(disabled_by_default_tracing_category_, "OnIdleTaskPosted");
283 if (is_shutdown_)
284 return;
265 if (idle_task_runner_->RunsTasksOnCurrentThread()) { 285 if (idle_task_runner_->RunsTasksOnCurrentThread()) {
266 OnIdleTaskPostedOnMainThread(); 286 OnIdleTaskPostedOnMainThread();
267 } else { 287 } else {
268 helper_->ControlTaskRunner()->PostTask( 288 helper_->ControlTaskRunner()->PostTask(
269 FROM_HERE, on_idle_task_posted_closure_.callback()); 289 FROM_HERE, on_idle_task_posted_closure_.callback());
270 } 290 }
271 } 291 }
272 292
273 void IdleHelper::OnIdleTaskPostedOnMainThread() { 293 void IdleHelper::OnIdleTaskPostedOnMainThread() {
274 TRACE_EVENT0(disabled_by_default_tracing_category_, 294 TRACE_EVENT0(disabled_by_default_tracing_category_,
275 "OnIdleTaskPostedOnMainThread"); 295 "OnIdleTaskPostedOnMainThread");
296 if (is_shutdown_)
297 return;
276 if (state_.idle_period_state() == 298 if (state_.idle_period_state() ==
277 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) { 299 IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED) {
278 // Restart long idle period ticks. 300 // Restart long idle period ticks.
279 helper_->ControlTaskRunner()->PostTask( 301 helper_->ControlTaskRunner()->PostTask(
280 FROM_HERE, enable_next_long_idle_period_closure_.callback()); 302 FROM_HERE, enable_next_long_idle_period_closure_.callback());
281 } 303 }
282 } 304 }
283 305
284 base::TimeTicks IdleHelper::WillProcessIdleTask() { 306 base::TimeTicks IdleHelper::WillProcessIdleTask() {
285 helper_->CheckOnValidThread(); 307 helper_->CheckOnValidThread();
308 DCHECK(!is_shutdown_);
286 state_.TraceIdleIdleTaskStart(); 309 state_.TraceIdleIdleTaskStart();
287 return CurrentIdleTaskDeadline(); 310 return CurrentIdleTaskDeadline();
288 } 311 }
289 312
290 void IdleHelper::DidProcessIdleTask() { 313 void IdleHelper::DidProcessIdleTask() {
291 helper_->CheckOnValidThread(); 314 helper_->CheckOnValidThread();
315 if (is_shutdown_)
316 return;
292 state_.TraceIdleIdleTaskEnd(); 317 state_.TraceIdleIdleTaskEnd();
293 if (IsInLongIdlePeriod(state_.idle_period_state())) { 318 if (IsInLongIdlePeriod(state_.idle_period_state())) {
294 UpdateLongIdlePeriodStateAfterIdleTask(); 319 UpdateLongIdlePeriodStateAfterIdleTask();
295 } 320 }
296 } 321 }
297 322
298 // static 323 // static
299 bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) { 324 bool IdleHelper::IsInIdlePeriod(IdlePeriodState state) {
300 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD; 325 return state != IdlePeriodState::NOT_IN_IDLE_PERIOD;
301 } 326 }
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED: 493 case IdlePeriodState::IN_LONG_IDLE_PERIOD_PAUSED:
469 return "in_long_idle_period_paused"; 494 return "in_long_idle_period_paused";
470 default: 495 default:
471 NOTREACHED(); 496 NOTREACHED();
472 return nullptr; 497 return nullptr;
473 } 498 }
474 } 499 }
475 500
476 } // namespace scheduler 501 } // namespace scheduler
477 } // namespace blink 502 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698