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

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

Issue 2557083002: Run ScopedTaskScheduler tasks synchronously. (Closed)
Patch Set: CR gab #20 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 handed one). |message_loop_| will always be set and is
robliao 2016/12/13 03:27:42 s/handed one/provided one at construction/
fdoray 2016/12/13 19:14:14 Done.
71 // used by this TestTaskScheduler to run tasks.
72 std::unique_ptr<MessageLoop> message_loop_owned_;
73 MessageLoop* message_loop_;
74
75 // The SingleThreadTaskRunner associated with |message_loop_|.
76 const scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_ =
77 message_loop_->task_runner();
78
79 // Handles shutdown behaviors and sets up the environment to run a task.
80 internal::TaskTracker task_tracker_;
81
82 DISALLOW_COPY_AND_ASSIGN(TestTaskScheduler);
83 };
84
85 class TestTaskSchedulerTaskRunner : public SingleThreadTaskRunner {
86 public:
87 TestTaskSchedulerTaskRunner(TestTaskScheduler* task_scheduler,
88 ExecutionMode execution_mode,
89 TaskTraits traits);
90
91 // SingleThreadTaskRunner:
92 bool PostDelayedTask(const tracked_objects::Location& from_here,
93 const Closure& closure,
94 TimeDelta delay) override;
95 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
96 const Closure& closure,
97 TimeDelta delay) override;
98 bool RunsTasksOnCurrentThread() const override;
99
100 private:
101 ~TestTaskSchedulerTaskRunner() override;
102
103 TestTaskScheduler* const task_scheduler_;
104 const ExecutionMode execution_mode_;
105 const SequenceToken sequence_token_;
106 const TaskTraits traits_;
107
108 DISALLOW_COPY_AND_ASSIGN(TestTaskSchedulerTaskRunner);
109 };
110
111 TestTaskScheduler::TestTaskScheduler(MessageLoop* external_message_loop)
112 : message_loop_owned_(external_message_loop ? nullptr
113 : MakeUnique<MessageLoop>()),
114 message_loop_(message_loop_owned_ ? message_loop_owned_.get()
115 : external_message_loop) {}
116
117 TestTaskScheduler::~TestTaskScheduler() {
118 // Prevent the RunUntilIdle() call below from running SKIP_ON_SHUTDOWN and
119 // CONTINUE_ON_SHUTDOWN tasks.
120 task_tracker_.SetHasShutdownStartedForTesting();
121
122 // Run pending BLOCK_SHUTDOWN tasks.
123 RunLoop().RunUntilIdle();
124 }
125
126 void TestTaskScheduler::PostTaskWithTraits(
127 const tracked_objects::Location& from_here,
128 const TaskTraits& traits,
129 const Closure& task) {
130 CreateTaskRunnerWithTraits(traits)->PostTask(from_here, task);
131 }
132
133 scoped_refptr<TaskRunner> TestTaskScheduler::CreateTaskRunnerWithTraits(
134 const TaskTraits& traits) {
135 return make_scoped_refptr(
136 new TestTaskSchedulerTaskRunner(this, ExecutionMode::PARALLEL, traits));
137 }
138
139 scoped_refptr<SequencedTaskRunner>
140 TestTaskScheduler::CreateSequencedTaskRunnerWithTraits(
141 const TaskTraits& traits) {
142 return make_scoped_refptr(
143 new TestTaskSchedulerTaskRunner(this, ExecutionMode::SEQUENCED, traits));
144 }
145
146 scoped_refptr<SingleThreadTaskRunner>
147 TestTaskScheduler::CreateSingleThreadTaskRunnerWithTraits(
148 const TaskTraits& traits) {
149 return make_scoped_refptr(new TestTaskSchedulerTaskRunner(
150 this, ExecutionMode::SINGLE_THREADED, traits));
151 }
152
153 std::vector<const HistogramBase*> TestTaskScheduler::GetHistograms() const {
154 NOTREACHED();
155 return std::vector<const HistogramBase*>();
156 }
157
158 void TestTaskScheduler::Shutdown() {
159 NOTREACHED();
160 }
161
162 void TestTaskScheduler::FlushForTesting() {
163 NOTREACHED();
164 }
165
166 bool TestTaskScheduler::PostTask(std::unique_ptr<internal::Task> task,
167 const SequenceToken& sequence_token) {
168 DCHECK(task);
169 if (!task_tracker_.WillPostTask(task.get()))
170 return false;
171 internal::Task* const task_ptr = task.get();
172 return message_loop_task_runner_->PostDelayedTask(
173 task_ptr->posted_from, Bind(&TestTaskScheduler::RunTask, Unretained(this),
174 Passed(std::move(task)), sequence_token),
175 task_ptr->delay);
176 }
177
178 void TestTaskScheduler::RunTask(std::unique_ptr<internal::Task> task,
179 const SequenceToken& sequence_token) {
180 // Clear the MessageLoop TaskRunner to allow TaskTracker to register a
181 // Thread/SequencedTaskRunnerHandle as appropriate.
182 MessageLoop::current()->SetTaskRunner(nullptr);
183
184 // Run the task.
185 task_tracker_.RunTask(std::move(task), sequence_token.IsValid()
186 ? sequence_token
187 : SequenceToken::Create());
188
189 // Restore the MessageLoop TaskRunner.
190 MessageLoop::current()->SetTaskRunner(message_loop_task_runner_);
191 }
192
193 bool TestTaskScheduler::RunsTasksOnCurrentThread() const {
194 return message_loop_task_runner_->RunsTasksOnCurrentThread();
195 }
196
197 TestTaskSchedulerTaskRunner::TestTaskSchedulerTaskRunner(
198 TestTaskScheduler* task_scheduler,
199 ExecutionMode execution_mode,
200 TaskTraits traits)
201 : task_scheduler_(task_scheduler),
202 execution_mode_(execution_mode),
203 sequence_token_(execution_mode == ExecutionMode::PARALLEL
204 ? SequenceToken()
205 : SequenceToken::Create()),
206 traits_(traits) {}
207
208 bool TestTaskSchedulerTaskRunner::PostDelayedTask(
209 const tracked_objects::Location& from_here,
210 const Closure& closure,
211 TimeDelta delay) {
212 auto task = MakeUnique<internal::Task>(from_here, closure, traits_, delay);
213 if (execution_mode_ == ExecutionMode::SEQUENCED)
214 task->sequenced_task_runner_ref = make_scoped_refptr(this);
215 else if (execution_mode_ == ExecutionMode::SINGLE_THREADED)
216 task->single_thread_task_runner_ref = make_scoped_refptr(this);
217 return task_scheduler_->PostTask(std::move(task), sequence_token_);
218 }
219
220 bool TestTaskSchedulerTaskRunner::PostNonNestableDelayedTask(
221 const tracked_objects::Location& from_here,
222 const Closure& closure,
223 TimeDelta delay) {
224 // Tasks are never nested within the task scheduler.
225 return PostDelayedTask(from_here, closure, delay);
226 }
227
228 bool TestTaskSchedulerTaskRunner::RunsTasksOnCurrentThread() const {
229 if (execution_mode_ == ExecutionMode::PARALLEL)
230 return task_scheduler_->RunsTasksOnCurrentThread();
231 return sequence_token_ == SequenceToken::GetForCurrentThread();
232 }
233
234 TestTaskSchedulerTaskRunner::~TestTaskSchedulerTaskRunner() = default;
235
236 } // namespace
237
238 ScopedTaskScheduler::ScopedTaskScheduler() : ScopedTaskScheduler(nullptr) {}
239
240 ScopedTaskScheduler::ScopedTaskScheduler(MessageLoop* external_message_loop) {
19 DCHECK(!TaskScheduler::GetInstance()); 241 DCHECK(!TaskScheduler::GetInstance());
20 242 TaskScheduler::SetInstance(
21 // Create a TaskScheduler with a single thread to make tests deterministic. 243 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(); 244 task_scheduler_ = TaskScheduler::GetInstance();
32 } 245 }
33 246
34 ScopedTaskScheduler::~ScopedTaskScheduler() { 247 ScopedTaskScheduler::~ScopedTaskScheduler() {
248 DCHECK(thread_checker_.CalledOnValidThread());
35 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance()); 249 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance());
36 TaskScheduler::GetInstance()->Shutdown();
37 TaskScheduler::GetInstance()->JoinForTesting();
38 TaskScheduler::SetInstance(nullptr); 250 TaskScheduler::SetInstance(nullptr);
39 } 251 }
40 252
41 } // namespace test 253 } // namespace test
42 } // namespace base 254 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698