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

Side by Side Diff: base/test/scoped_task_scheduler.cc

Issue 2557083002: Run ScopedTaskScheduler tasks synchronously. (Closed)
Patch Set: add owners Created 4 years 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/test/scoped_task_scheduler.h" 5 #include "base/test/scoped_task_scheduler.h"
6 6
7 #include <memory>
8 #include <utility>
7 #include <vector> 9 #include <vector>
8 10
9 #include "base/bind.h" 11 #include "base/bind.h"
10 #include "base/task_scheduler/scheduler_worker_pool_params.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/histogram_base.h"
17 #include "base/run_loop.h"
18 #include "base/sequence_token.h"
19 #include "base/sequenced_task_runner.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/task_runner.h"
22 #include "base/task_scheduler/task.h"
11 #include "base/task_scheduler/task_scheduler.h" 23 #include "base/task_scheduler/task_scheduler.h"
12 #include "base/threading/platform_thread.h" 24 #include "base/task_scheduler/task_tracker.h"
13 #include "base/time/time.h" 25 #include "base/threading/thread_task_runner_handle.h"
14 26
15 namespace base { 27 namespace base {
16 namespace test { 28 namespace test {
17 29
18 ScopedTaskScheduler::ScopedTaskScheduler() { 30 namespace {
31
32 enum class ExecutionMode { PARALLEL, SEQUENCED, SINGLE_THREADED };
33
34 class TestTaskScheduler : public TaskScheduler {
35 public:
36 // |external_message_loop| is an externally provided MessageLoop on which to
37 // run tasks. A MessageLoop will be created by TestTaskScheduler if
38 // |external_message_loop| is nullptr.
39 explicit TestTaskScheduler(MessageLoop* external_message_loop);
40 ~TestTaskScheduler() override;
41
42 // TaskScheduler:
43 void PostTaskWithTraits(const tracked_objects::Location& from_here,
44 const TaskTraits& traits,
45 const Closure& task) override;
46 scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits(
47 const TaskTraits& traits) override;
48 scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits(
49 const TaskTraits& traits) override;
50 scoped_refptr<SingleThreadTaskRunner> CreateSingleThreadTaskRunnerWithTraits(
51 const TaskTraits& traits) override;
52 std::vector<const HistogramBase*> GetHistograms() const override;
53 void Shutdown() override;
54 void FlushForTesting() override;
55
56 // Posts |task| to this TaskScheduler with |sequence_token|. Returns true on
57 // success.
58 bool PostTask(std::unique_ptr<internal::Task> task,
59 const SequenceToken& sequence_token);
60
61 // Runs |task| with |sequence_token| using this TaskScheduler's TaskTracker.
62 void RunTask(std::unique_ptr<internal::Task> task,
63 const SequenceToken& sequence_token);
64
65 // Returns true if this TaskScheduler runs its tasks on the current thread.
66 bool RunsTasksOnCurrentThread() const;
67
68 private:
69 // |message_loop_owned_| will be non-null if this TestTaskScheduler owns the
70 // MessageLoop (wasn't provided an external one at construction).
71 // |message_loop_| will always be set and is used by this TestTaskScheduler to
72 // run tasks.
73 std::unique_ptr<MessageLoop> message_loop_owned_;
74 MessageLoop* message_loop_;
75
76 // The SingleThreadTaskRunner associated with |message_loop_|.
77 const scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_ =
78 message_loop_->task_runner();
79
80 // Handles shutdown behaviors and sets up the environment to run a task.
81 internal::TaskTracker task_tracker_;
82
83 DISALLOW_COPY_AND_ASSIGN(TestTaskScheduler);
84 };
85
86 class TestTaskSchedulerTaskRunner : public SingleThreadTaskRunner {
87 public:
88 TestTaskSchedulerTaskRunner(TestTaskScheduler* task_scheduler,
89 ExecutionMode execution_mode,
90 TaskTraits traits);
91
92 // SingleThreadTaskRunner:
93 bool PostDelayedTask(const tracked_objects::Location& from_here,
94 const Closure& closure,
95 TimeDelta delay) override;
96 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
97 const Closure& closure,
98 TimeDelta delay) override;
99 bool RunsTasksOnCurrentThread() const override;
100
101 private:
102 ~TestTaskSchedulerTaskRunner() override;
103
104 TestTaskScheduler* const task_scheduler_;
105 const ExecutionMode execution_mode_;
106 const SequenceToken sequence_token_;
107 const TaskTraits traits_;
108
109 DISALLOW_COPY_AND_ASSIGN(TestTaskSchedulerTaskRunner);
110 };
111
112 TestTaskScheduler::TestTaskScheduler(MessageLoop* external_message_loop)
113 : message_loop_owned_(external_message_loop ? nullptr
114 : MakeUnique<MessageLoop>()),
115 message_loop_(message_loop_owned_ ? message_loop_owned_.get()
116 : external_message_loop) {}
117
118 TestTaskScheduler::~TestTaskScheduler() {
119 // Prevent the RunUntilIdle() call below from running SKIP_ON_SHUTDOWN and
120 // CONTINUE_ON_SHUTDOWN tasks.
121 task_tracker_.SetHasShutdownStartedForTesting();
122
123 // Run pending BLOCK_SHUTDOWN tasks.
124 RunLoop().RunUntilIdle();
125 }
126
127 void TestTaskScheduler::PostTaskWithTraits(
128 const tracked_objects::Location& from_here,
129 const TaskTraits& traits,
130 const Closure& task) {
131 CreateTaskRunnerWithTraits(traits)->PostTask(from_here, task);
132 }
133
134 scoped_refptr<TaskRunner> TestTaskScheduler::CreateTaskRunnerWithTraits(
135 const TaskTraits& traits) {
136 return make_scoped_refptr(
137 new TestTaskSchedulerTaskRunner(this, ExecutionMode::PARALLEL, traits));
138 }
139
140 scoped_refptr<SequencedTaskRunner>
141 TestTaskScheduler::CreateSequencedTaskRunnerWithTraits(
142 const TaskTraits& traits) {
143 return make_scoped_refptr(
144 new TestTaskSchedulerTaskRunner(this, ExecutionMode::SEQUENCED, traits));
145 }
146
147 scoped_refptr<SingleThreadTaskRunner>
148 TestTaskScheduler::CreateSingleThreadTaskRunnerWithTraits(
149 const TaskTraits& traits) {
150 return make_scoped_refptr(new TestTaskSchedulerTaskRunner(
151 this, ExecutionMode::SINGLE_THREADED, traits));
152 }
153
154 std::vector<const HistogramBase*> TestTaskScheduler::GetHistograms() const {
155 NOTREACHED();
156 return std::vector<const HistogramBase*>();
dcheng 2016/12/15 06:47:36 Alternatively, {} suffices. I don't feel strongly
fdoray 2016/12/15 16:39:32 Done.
fdoray 2016/12/15 20:49:33 Breaks linux_chromium_compile_dbg_ng and linux_
157 }
158
159 void TestTaskScheduler::Shutdown() {
160 NOTREACHED();
161 }
162
163 void TestTaskScheduler::FlushForTesting() {
164 NOTREACHED();
165 }
166
167 bool TestTaskScheduler::PostTask(std::unique_ptr<internal::Task> task,
168 const SequenceToken& sequence_token) {
169 DCHECK(task);
170 if (!task_tracker_.WillPostTask(task.get()))
171 return false;
172 internal::Task* const task_ptr = task.get();
173 return message_loop_task_runner_->PostDelayedTask(
174 task_ptr->posted_from, Bind(&TestTaskScheduler::RunTask, Unretained(this),
175 Passed(std::move(task)), sequence_token),
dcheng 2016/12/15 06:47:36 I'd prefer to just write this as Passed(&task) to
fdoray 2016/12/15 16:39:32 Done.
gab 2016/12/15 17:56:29 I thought https://groups.google.com/a/chromium.org
176 task_ptr->delay);
177 }
178
179 void TestTaskScheduler::RunTask(std::unique_ptr<internal::Task> task,
180 const SequenceToken& sequence_token) {
181 // Clear the MessageLoop TaskRunner to allow TaskTracker to register a
182 // Thread/SequencedTaskRunnerHandle as appropriate.
183 MessageLoop::current()->SetTaskRunner(nullptr);
184
185 // Run the task.
186 task_tracker_.RunTask(std::move(task), sequence_token.IsValid()
187 ? sequence_token
188 : SequenceToken::Create());
189
190 // Restore the MessageLoop TaskRunner.
191 MessageLoop::current()->SetTaskRunner(message_loop_task_runner_);
192 }
193
194 bool TestTaskScheduler::RunsTasksOnCurrentThread() const {
195 return message_loop_task_runner_->RunsTasksOnCurrentThread();
196 }
197
198 TestTaskSchedulerTaskRunner::TestTaskSchedulerTaskRunner(
199 TestTaskScheduler* task_scheduler,
200 ExecutionMode execution_mode,
201 TaskTraits traits)
202 : task_scheduler_(task_scheduler),
203 execution_mode_(execution_mode),
204 sequence_token_(execution_mode == ExecutionMode::PARALLEL
205 ? SequenceToken()
206 : SequenceToken::Create()),
207 traits_(traits) {}
208
209 bool TestTaskSchedulerTaskRunner::PostDelayedTask(
210 const tracked_objects::Location& from_here,
211 const Closure& closure,
212 TimeDelta delay) {
213 auto task = MakeUnique<internal::Task>(from_here, closure, traits_, delay);
214 if (execution_mode_ == ExecutionMode::SEQUENCED)
215 task->sequenced_task_runner_ref = make_scoped_refptr(this);
216 else if (execution_mode_ == ExecutionMode::SINGLE_THREADED)
217 task->single_thread_task_runner_ref = make_scoped_refptr(this);
218 return task_scheduler_->PostTask(std::move(task), sequence_token_);
219 }
220
221 bool TestTaskSchedulerTaskRunner::PostNonNestableDelayedTask(
222 const tracked_objects::Location& from_here,
223 const Closure& closure,
224 TimeDelta delay) {
225 // Tasks are never nested within the task scheduler.
226 return PostDelayedTask(from_here, closure, delay);
227 }
228
229 bool TestTaskSchedulerTaskRunner::RunsTasksOnCurrentThread() const {
230 if (execution_mode_ == ExecutionMode::PARALLEL)
231 return task_scheduler_->RunsTasksOnCurrentThread();
232 return sequence_token_ == SequenceToken::GetForCurrentThread();
233 }
234
235 TestTaskSchedulerTaskRunner::~TestTaskSchedulerTaskRunner() = default;
236
237 } // namespace
238
239 ScopedTaskScheduler::ScopedTaskScheduler() : ScopedTaskScheduler(nullptr) {}
240
241 ScopedTaskScheduler::ScopedTaskScheduler(MessageLoop* external_message_loop) {
19 DCHECK(!TaskScheduler::GetInstance()); 242 DCHECK(!TaskScheduler::GetInstance());
20 243 TaskScheduler::SetInstance(
21 // Create a TaskScheduler with a single thread to make tests deterministic. 244 MakeUnique<TestTaskScheduler>(external_message_loop));
22 constexpr int kMaxThreads = 1;
23 std::vector<SchedulerWorkerPoolParams> worker_pool_params_vector;
24 worker_pool_params_vector.emplace_back(
25 "Simple", ThreadPriority::NORMAL,
26 SchedulerWorkerPoolParams::StandbyThreadPolicy::LAZY, kMaxThreads,
27 TimeDelta::Max());
28 TaskScheduler::CreateAndSetDefaultTaskScheduler(
29 worker_pool_params_vector,
30 Bind([](const TaskTraits&) -> size_t { return 0; }));
31 task_scheduler_ = TaskScheduler::GetInstance(); 245 task_scheduler_ = TaskScheduler::GetInstance();
32 } 246 }
33 247
34 ScopedTaskScheduler::~ScopedTaskScheduler() { 248 ScopedTaskScheduler::~ScopedTaskScheduler() {
249 DCHECK(thread_checker_.CalledOnValidThread());
35 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance()); 250 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance());
36 TaskScheduler::GetInstance()->Shutdown();
37 TaskScheduler::GetInstance()->JoinForTesting();
38 TaskScheduler::SetInstance(nullptr); 251 TaskScheduler::SetInstance(nullptr);
39 } 252 }
40 253
41 } // namespace test 254 } // namespace test
42 } // namespace base 255 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698