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

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

Issue 2557083002: Run ScopedTaskScheduler tasks synchronously. (Closed)
Patch Set: git cl try 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 "build/build_config.h"
26
27 #if defined(OS_POSIX) && !defined(OS_NACL_SFI)
28 #include "base/files/file_descriptor_watcher_posix.h"
29 #endif
14 30
15 namespace base { 31 namespace base {
16 namespace test { 32 namespace test {
17 33
18 ScopedTaskScheduler::ScopedTaskScheduler() { 34 namespace {
35
36 enum class ExecutionMode { PARALLEL, SEQUENCED, SINGLE_THREADED };
37
38 class TestTaskScheduler : public TaskScheduler {
39 public:
40 TestTaskScheduler(ScopedTaskScheduler::Options options);
41 ~TestTaskScheduler() override;
42
43 // TaskScheduler:
44 void PostTaskWithTraits(const tracked_objects::Location& from_here,
45 const TaskTraits& traits,
46 const Closure& task) override;
47 scoped_refptr<TaskRunner> CreateTaskRunnerWithTraits(
48 const TaskTraits& traits) override;
49 scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits(
50 const TaskTraits& traits) override;
51 scoped_refptr<SingleThreadTaskRunner> CreateSingleThreadTaskRunnerWithTraits(
52 const TaskTraits& traits) override;
53 std::vector<const HistogramBase*> GetHistograms() const override;
54 void Shutdown() override;
55 void FlushForTesting() override;
56
57 // Posts |task| to this TaskScheduler with |sequence_token|.
robliao 2016/12/09 01:32:54 Nit: Add what the bool (return value) indicates.
fdoray 2016/12/09 16:26:41 Done.
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 // The MessageLoop that runs all tasks posted to this TaskScheduler.
70 MessageLoop message_loop_;
71
72 // The SingleThreadTaskRunner associated with |message_loop_|.
73 const scoped_refptr<SingleThreadTaskRunner> message_loop_task_runner_ =
74 message_loop_.task_runner();
75
76 // Handles shutdown behaviors and sets up the environment to run a task.
77 internal::TaskTracker task_tracker_;
78
79 #if defined(OS_POSIX) && !defined(OS_NACL_SFI)
80 // Allow usage of FileDescriptorWatcher within the scope of
81 // ScopedTaskScheduler if it runs on a MessageLoopForIO.
82 //
83 // Note: Initializing a single FileDescriptorWatcher for the scope of
84 // ScopedTaskScheduler rather than using TaskTrackerPosix to initialize a
85 // FileDescriptorWatcher in the scope in which tasks run makes it easier to
86 // watch file descriptors from outside of TaskScheduler tasks.
gab 2016/12/08 20:15:45 But doesn't this now give an API to other threads
fdoray 2016/12/09 16:26:41 Removed. Offline discussion: We will stop initial
87 std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_ =
88 message_loop_.IsType(MessageLoop::TYPE_IO)
89 ? MakeUnique<FileDescriptorWatcher>(message_loop_.task_runner())
90 : nullptr;
91 #endif
92
93 DISALLOW_COPY_AND_ASSIGN(TestTaskScheduler);
94 };
95
96 class TestTaskSchedulerTaskRunner : public SingleThreadTaskRunner {
97 public:
98 TestTaskSchedulerTaskRunner(TestTaskScheduler* task_scheduler,
99 ExecutionMode execution_mode,
100 TaskTraits traits);
101
102 // SingleThreadTaskRunner:
103 bool PostDelayedTask(const tracked_objects::Location& from_here,
104 const Closure& closure,
105 TimeDelta delay) override;
106 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
107 const Closure& closure,
108 TimeDelta delay) override;
109 bool RunsTasksOnCurrentThread() const override;
110
111 private:
112 ~TestTaskSchedulerTaskRunner() override;
113
114 TestTaskScheduler* const task_scheduler_;
115 const ExecutionMode execution_mode_;
116 const SequenceToken sequence_token_;
117 const TaskTraits traits_;
118
119 DISALLOW_COPY_AND_ASSIGN(TestTaskSchedulerTaskRunner);
120 };
121
122 TestTaskScheduler::TestTaskScheduler(ScopedTaskScheduler::Options options)
123 : message_loop_(options & ScopedTaskScheduler::UI_MAIN_LOOP
124 ? MessageLoop::TYPE_UI
125 : MessageLoop::TYPE_IO) {}
126
127 TestTaskScheduler::~TestTaskScheduler() {
128 // Prevent the RunUntilIdle() call below from running SKIP_ON_SHUTDOWN and
129 // CONTINUE_ON_SHUTDOWN tasks.
130 task_tracker_.SetHasShutdownStartedForTesting();
131
132 // Run pending BLOCK_SHUTDOWN tasks.
133 RunLoop().RunUntilIdle();
134 }
135
136 void TestTaskScheduler::PostTaskWithTraits(
137 const tracked_objects::Location& from_here,
138 const TaskTraits& traits,
139 const Closure& task) {
140 CreateTaskRunnerWithTraits(traits)->PostTask(from_here, task);
141 }
142
143 scoped_refptr<TaskRunner> TestTaskScheduler::CreateTaskRunnerWithTraits(
144 const TaskTraits& traits) {
145 return make_scoped_refptr(
146 new TestTaskSchedulerTaskRunner(this, ExecutionMode::PARALLEL, traits));
147 }
148
149 scoped_refptr<SequencedTaskRunner>
150 TestTaskScheduler::CreateSequencedTaskRunnerWithTraits(
151 const TaskTraits& traits) {
152 return make_scoped_refptr(
153 new TestTaskSchedulerTaskRunner(this, ExecutionMode::SEQUENCED, traits));
154 }
155
156 scoped_refptr<SingleThreadTaskRunner>
157 TestTaskScheduler::CreateSingleThreadTaskRunnerWithTraits(
158 const TaskTraits& traits) {
159 return make_scoped_refptr(new TestTaskSchedulerTaskRunner(
160 this, ExecutionMode::SINGLE_THREADED, traits));
161 }
162
163 std::vector<const HistogramBase*> TestTaskScheduler::GetHistograms() const {
164 NOTREACHED();
165 return std::vector<const HistogramBase*>();
166 }
167
168 void TestTaskScheduler::Shutdown() {
169 NOTREACHED();
170 }
171
172 void TestTaskScheduler::FlushForTesting() {
173 NOTREACHED();
174 }
175
176 bool TestTaskScheduler::PostTask(std::unique_ptr<internal::Task> task,
177 const SequenceToken& sequence_token) {
178 DCHECK(task);
179 if (!task_tracker_.WillPostTask(task.get()))
180 return false;
181 internal::Task* const task_ptr = task.get();
182 return message_loop_task_runner_->PostDelayedTask(
183 task_ptr->posted_from, Bind(&TestTaskScheduler::RunTask, Unretained(this),
184 Passed(std::move(task)), sequence_token),
185 task_ptr->delay);
186 }
187
188 void TestTaskScheduler::RunTask(std::unique_ptr<internal::Task> task,
189 const SequenceToken& sequence_token) {
190 // Clear the MessageLoop TaskRunner to allow TaskTracker to register a
191 // Thread/SequencedTaskRunnerHandle as appropriate.
192 message_loop_.SetTaskRunner(nullptr);
193
194 // Run the task.
195 task_tracker_.RunTask(std::move(task), sequence_token.IsValid()
196 ? sequence_token
197 : SequenceToken::Create());
198
199 // Restore the MessageLoop TaskRunner.
200 message_loop_.SetTaskRunner(message_loop_task_runner_);
201 }
202
203 bool TestTaskScheduler::RunsTasksOnCurrentThread() const {
204 return message_loop_task_runner_->RunsTasksOnCurrentThread();
205 }
206
207 TestTaskSchedulerTaskRunner::TestTaskSchedulerTaskRunner(
208 TestTaskScheduler* task_scheduler,
209 ExecutionMode execution_mode,
210 TaskTraits traits)
211 : task_scheduler_(task_scheduler),
212 execution_mode_(execution_mode),
213 sequence_token_(execution_mode == ExecutionMode::PARALLEL
214 ? SequenceToken()
215 : SequenceToken::Create()),
216 traits_(traits) {}
217
218 bool TestTaskSchedulerTaskRunner::PostDelayedTask(
219 const tracked_objects::Location& from_here,
220 const Closure& closure,
221 TimeDelta delay) {
222 auto task = MakeUnique<internal::Task>(from_here, closure, traits_, delay);
223 if (execution_mode_ == ExecutionMode::SEQUENCED)
224 task->sequenced_task_runner_ref = make_scoped_refptr(this);
225 else if (execution_mode_ == ExecutionMode::SINGLE_THREADED)
226 task->single_thread_task_runner_ref = make_scoped_refptr(this);
227 return task_scheduler_->PostTask(std::move(task), sequence_token_);
228 }
229
230 bool TestTaskSchedulerTaskRunner::PostNonNestableDelayedTask(
231 const tracked_objects::Location& from_here,
232 const Closure& closure,
233 TimeDelta delay) {
234 // Tasks are never nested within the task scheduler.
235 return PostDelayedTask(from_here, closure, delay);
236 }
237
238 bool TestTaskSchedulerTaskRunner::RunsTasksOnCurrentThread() const {
239 if (execution_mode_ == ExecutionMode::PARALLEL)
240 return task_scheduler_->RunsTasksOnCurrentThread();
241 return sequence_token_ == SequenceToken::GetForCurrentThread();
242 }
243
244 TestTaskSchedulerTaskRunner::~TestTaskSchedulerTaskRunner() = default;
245
246 } // namespace
247
248 ScopedTaskScheduler::ScopedTaskScheduler()
249 : ScopedTaskScheduler(Options::DEFAULT) {}
250
251 ScopedTaskScheduler::ScopedTaskScheduler(Options options) {
19 DCHECK(!TaskScheduler::GetInstance()); 252 DCHECK(!TaskScheduler::GetInstance());
20 253 TaskScheduler::SetInstance(MakeUnique<TestTaskScheduler>(options));
21 // Create a TaskScheduler with a single thread to make tests deterministic.
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(); 254 task_scheduler_ = TaskScheduler::GetInstance();
32 } 255 }
33 256
34 ScopedTaskScheduler::~ScopedTaskScheduler() { 257 ScopedTaskScheduler::~ScopedTaskScheduler() {
258 DCHECK(thread_checker_.CalledOnValidThread());
35 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance()); 259 DCHECK_EQ(task_scheduler_, TaskScheduler::GetInstance());
36 TaskScheduler::GetInstance()->Shutdown();
37 TaskScheduler::GetInstance()->JoinForTesting();
38 TaskScheduler::SetInstance(nullptr); 260 TaskScheduler::SetInstance(nullptr);
39 } 261 }
40 262
41 } // namespace test 263 } // namespace test
42 } // namespace base 264 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698