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

Side by Side Diff: base/task_scheduler/task_tracker.cc

Issue 2362253002: TaskScheduler: Add FlushForTesting(). (Closed)
Patch Set: self-review Created 4 years, 2 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "base/task_scheduler/task_tracker.h" 5 #include "base/task_scheduler/task_tracker.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/atomicops.h"
10 #include "base/callback.h" 9 #include "base/callback.h"
11 #include "base/debug/task_annotator.h" 10 #include "base/debug/task_annotator.h"
12 #include "base/logging.h" 11 #include "base/logging.h"
13 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
14 #include "base/sequence_token.h" 13 #include "base/sequence_token.h"
14 #include "base/synchronization/condition_variable.h"
15 #include "base/threading/sequenced_task_runner_handle.h" 15 #include "base/threading/sequenced_task_runner_handle.h"
16 #include "base/threading/thread_restrictions.h" 16 #include "base/threading/thread_restrictions.h"
17 #include "base/threading/thread_task_runner_handle.h" 17 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/trace_event/trace_event.h" 18 #include "base/trace_event/trace_event.h"
19 19
20 namespace base { 20 namespace base {
21 namespace internal { 21 namespace internal {
22 22
23 namespace { 23 namespace {
24 24
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 // modify-write) semantics however. For example, if two threads are racing to 121 // modify-write) semantics however. For example, if two threads are racing to
122 // call IncrementNumTasksBlockingShutdown() and StartShutdown() respectively, 122 // call IncrementNumTasksBlockingShutdown() and StartShutdown() respectively,
123 // either the first thread will win and the StartShutdown() call will see the 123 // either the first thread will win and the StartShutdown() call will see the
124 // blocking task or the second thread will win and 124 // blocking task or the second thread will win and
125 // IncrementNumTasksBlockingShutdown() will know that shutdown has started. 125 // IncrementNumTasksBlockingShutdown() will know that shutdown has started.
126 subtle::Atomic32 bits_ = 0; 126 subtle::Atomic32 bits_ = 0;
127 127
128 DISALLOW_COPY_AND_ASSIGN(State); 128 DISALLOW_COPY_AND_ASSIGN(State);
129 }; 129 };
130 130
131 TaskTracker::TaskTracker() : state_(new State) {} 131 TaskTracker::TaskTracker()
132 : state_(new State),
133 flush_for_testing_cv_(flush_for_testing_lock_.CreateConditionVariable()),
134 shutdown_lock_(&flush_for_testing_lock_) {}
132 TaskTracker::~TaskTracker() = default; 135 TaskTracker::~TaskTracker() = default;
133 136
134 void TaskTracker::Shutdown() { 137 void TaskTracker::Shutdown() {
138 PerformShutdown();
139 DCHECK(IsShutdownComplete());
140
141 // Unblock FlushForTesting() when shutdown completes.
142 AutoSchedulerLock auto_lock(flush_for_testing_lock_);
143 flush_for_testing_cv_->Signal();
144 }
145
146 void TaskTracker::FlushForTesting() {
147 AutoSchedulerLock auto_lock(flush_for_testing_lock_);
148 while (subtle::NoBarrier_Load(&num_pending_undelayed_tasks_) != 0 &&
149 !IsShutdownComplete()) {
150 flush_for_testing_cv_->Wait();
151 }
152 }
153
154 bool TaskTracker::WillPostTask(const Task* task) {
155 DCHECK(task);
156
157 if (!BeforePostTask(task->traits.shutdown_behavior()))
158 return false;
159
160 if (task->delayed_run_time.is_null())
161 subtle::NoBarrier_AtomicIncrement(&num_pending_undelayed_tasks_, 1);
162
163 debug::TaskAnnotator task_annotator;
164 task_annotator.DidQueueTask(kQueueFunctionName, *task);
165
166 return true;
167 }
168
169 bool TaskTracker::RunTask(const Task* task,
170 const SequenceToken& sequence_token) {
171 DCHECK(task);
172 DCHECK(sequence_token.IsValid());
173
174 const TaskShutdownBehavior shutdown_behavior =
175 task->traits.shutdown_behavior();
176 const bool can_run_task = BeforeRunTask(shutdown_behavior);
177
178 if (can_run_task) {
179 // All tasks run through here and the scheduler itself doesn't use
180 // singletons. Therefore, it isn't necessary to reset the singleton allowed
181 // bit after running the task.
182 ThreadRestrictions::SetSingletonAllowed(
183 task->traits.shutdown_behavior() !=
184 TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN);
185
186 {
187 // Set up SequenceToken as expected for the scope of the task.
188 ScopedSetSequenceTokenForCurrentThread
189 scoped_set_sequence_token_for_current_thread(sequence_token);
190
191 // Set up TaskRunnerHandle as expected for the scope of the task.
192 std::unique_ptr<SequencedTaskRunnerHandle> sequenced_task_runner_handle;
193 std::unique_ptr<ThreadTaskRunnerHandle> single_thread_task_runner_handle;
194 DCHECK(!task->sequenced_task_runner_ref ||
195 !task->single_thread_task_runner_ref);
196 if (task->sequenced_task_runner_ref) {
197 sequenced_task_runner_handle.reset(
198 new SequencedTaskRunnerHandle(task->sequenced_task_runner_ref));
199 } else if (task->single_thread_task_runner_ref) {
200 single_thread_task_runner_handle.reset(
201 new ThreadTaskRunnerHandle(task->single_thread_task_runner_ref));
202 }
203
204 TRACE_TASK_EXECUTION(kRunFunctionName, *task);
205
206 debug::TaskAnnotator task_annotator;
207 task_annotator.RunTask(kQueueFunctionName, *task);
208 }
209
210 AfterRunTask(shutdown_behavior);
211 }
212
213 if (task->delayed_run_time.is_null())
214 DecrementNumPendingUndelayedTasks();
215
216 return can_run_task;
217 }
218
219 bool TaskTracker::HasShutdownStarted() const {
220 return state_->HasShutdownStarted();
221 }
222
223 bool TaskTracker::IsShutdownComplete() const {
224 AutoSchedulerLock auto_lock(shutdown_lock_);
225 return shutdown_event_ && shutdown_event_->IsSignaled();
226 }
227
228 void TaskTracker::SetHasShutdownStartedForTesting() {
229 state_->StartShutdown();
230 }
231
232 void TaskTracker::PerformShutdown() {
135 { 233 {
136 AutoSchedulerLock auto_lock(shutdown_lock_); 234 AutoSchedulerLock auto_lock(shutdown_lock_);
137 235
138 // This method can only be called once. 236 // This method can only be called once.
139 DCHECK(!shutdown_event_); 237 DCHECK(!shutdown_event_);
140 DCHECK(!num_block_shutdown_tasks_posted_during_shutdown_); 238 DCHECK(!num_block_shutdown_tasks_posted_during_shutdown_);
141 DCHECK(!state_->HasShutdownStarted()); 239 DCHECK(!state_->HasShutdownStarted());
142 240
143 shutdown_event_.reset( 241 shutdown_event_.reset(
144 new WaitableEvent(WaitableEvent::ResetPolicy::MANUAL, 242 new WaitableEvent(WaitableEvent::ResetPolicy::MANUAL,
(...skipping 30 matching lines...) Expand all
175 // posted during shutdown. Otherwise, the histogram has already been 273 // posted during shutdown. Otherwise, the histogram has already been
176 // recorded in BeforePostTask(). 274 // recorded in BeforePostTask().
177 if (num_block_shutdown_tasks_posted_during_shutdown_ < 275 if (num_block_shutdown_tasks_posted_during_shutdown_ <
178 kMaxBlockShutdownTasksPostedDuringShutdown) { 276 kMaxBlockShutdownTasksPostedDuringShutdown) {
179 RecordNumBlockShutdownTasksPostedDuringShutdown( 277 RecordNumBlockShutdownTasksPostedDuringShutdown(
180 num_block_shutdown_tasks_posted_during_shutdown_); 278 num_block_shutdown_tasks_posted_during_shutdown_);
181 } 279 }
182 } 280 }
183 } 281 }
184 282
185 bool TaskTracker::WillPostTask(const Task* task) {
186 DCHECK(task);
187
188 if (!BeforePostTask(task->traits.shutdown_behavior()))
189 return false;
190
191 debug::TaskAnnotator task_annotator;
192 task_annotator.DidQueueTask(kQueueFunctionName, *task);
193
194 return true;
195 }
196
197 bool TaskTracker::RunTask(const Task* task,
198 const SequenceToken& sequence_token) {
199 DCHECK(task);
200 DCHECK(sequence_token.IsValid());
201
202 const TaskShutdownBehavior shutdown_behavior =
203 task->traits.shutdown_behavior();
204 if (!BeforeRunTask(shutdown_behavior))
205 return false;
206
207 // All tasks run through here and the scheduler itself doesn't use singletons.
208 // Therefore, it isn't necessary to reset the singleton allowed bit after
209 // running the task.
210 ThreadRestrictions::SetSingletonAllowed(
211 task->traits.shutdown_behavior() !=
212 TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN);
213
214 {
215 // Set up SequenceToken as expected for the scope of the task.
216 ScopedSetSequenceTokenForCurrentThread
217 scoped_set_sequence_token_for_current_thread(sequence_token);
218
219 // Set up TaskRunnerHandle as expected for the scope of the task.
220 std::unique_ptr<SequencedTaskRunnerHandle> sequenced_task_runner_handle;
221 std::unique_ptr<ThreadTaskRunnerHandle> single_thread_task_runner_handle;
222 DCHECK(!task->sequenced_task_runner_ref ||
223 !task->single_thread_task_runner_ref);
224 if (task->sequenced_task_runner_ref) {
225 sequenced_task_runner_handle.reset(
226 new SequencedTaskRunnerHandle(task->sequenced_task_runner_ref));
227 } else if (task->single_thread_task_runner_ref) {
228 single_thread_task_runner_handle.reset(
229 new ThreadTaskRunnerHandle(task->single_thread_task_runner_ref));
230 }
231
232 TRACE_TASK_EXECUTION(kRunFunctionName, *task);
233
234 debug::TaskAnnotator task_annotator;
235 task_annotator.RunTask(kQueueFunctionName, *task);
236 }
237
238 AfterRunTask(shutdown_behavior);
239
240 return true;
241 }
242
243 bool TaskTracker::HasShutdownStarted() const {
244 return state_->HasShutdownStarted();
245 }
246
247 bool TaskTracker::IsShutdownComplete() const {
248 AutoSchedulerLock auto_lock(shutdown_lock_);
249 return shutdown_event_ && shutdown_event_->IsSignaled();
250 }
251
252 void TaskTracker::SetHasShutdownStartedForTesting() {
253 state_->StartShutdown();
254 }
255
256 bool TaskTracker::BeforePostTask(TaskShutdownBehavior shutdown_behavior) { 283 bool TaskTracker::BeforePostTask(TaskShutdownBehavior shutdown_behavior) {
257 if (shutdown_behavior == TaskShutdownBehavior::BLOCK_SHUTDOWN) { 284 if (shutdown_behavior == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
258 // BLOCK_SHUTDOWN tasks block shutdown between the moment they are posted 285 // BLOCK_SHUTDOWN tasks block shutdown between the moment they are posted
259 // and the moment they complete their execution. 286 // and the moment they complete their execution.
260 const bool shutdown_started = state_->IncrementNumTasksBlockingShutdown(); 287 const bool shutdown_started = state_->IncrementNumTasksBlockingShutdown();
261 288
262 if (shutdown_started) { 289 if (shutdown_started) {
263 AutoSchedulerLock auto_lock(shutdown_lock_); 290 AutoSchedulerLock auto_lock(shutdown_lock_);
264 291
265 // A BLOCK_SHUTDOWN task posted after shutdown has completed is an 292 // A BLOCK_SHUTDOWN task posted after shutdown has completed is an
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 void TaskTracker::OnBlockingShutdownTasksComplete() { 372 void TaskTracker::OnBlockingShutdownTasksComplete() {
346 AutoSchedulerLock auto_lock(shutdown_lock_); 373 AutoSchedulerLock auto_lock(shutdown_lock_);
347 374
348 // This method can only be called after shutdown has started. 375 // This method can only be called after shutdown has started.
349 DCHECK(state_->HasShutdownStarted()); 376 DCHECK(state_->HasShutdownStarted());
350 DCHECK(shutdown_event_); 377 DCHECK(shutdown_event_);
351 378
352 shutdown_event_->Signal(); 379 shutdown_event_->Signal();
353 } 380 }
354 381
382 void TaskTracker::DecrementNumPendingUndelayedTasks() {
383 const auto new_num_pending_undelayed_tasks =
384 subtle::NoBarrier_AtomicIncrement(&num_pending_undelayed_tasks_, -1);
385 DCHECK_GE(new_num_pending_undelayed_tasks, 0);
386 if (new_num_pending_undelayed_tasks == 0) {
387 AutoSchedulerLock auto_lock(flush_for_testing_lock_);
388 flush_for_testing_cv_->Signal();
389 }
390 }
391
355 } // namespace internal 392 } // namespace internal
356 } // namespace base 393 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698