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

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

Issue 1705943002: TaskScheduler [5/9] Task Tracker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_3_pq
Patch Set: CR robliao #61 Created 4 years, 8 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
« no previous file with comments | « base/task_scheduler/task_tracker.cc ('k') | base/task_scheduler/task_traits.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/task_scheduler/task_tracker.h"
6
7 #include <queue>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task_scheduler/task.h"
15 #include "base/task_scheduler/task_traits.h"
16 #include "base/task_scheduler/test_utils.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/threading/simple_thread.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace base {
22 namespace internal {
23
24 namespace {
25
26 // Calls TaskTracker::Shutdown() asynchronously.
27 class ThreadCallingShutdown : public SimpleThread {
28 public:
29 explicit ThreadCallingShutdown(TaskTracker* tracker)
30 : SimpleThread("ThreadCallingShutdown"),
31 tracker_(tracker),
32 has_returned_(true, false) {}
33
34 // Returns true once the async call to Shutdown() has returned.
35 bool has_returned() { return has_returned_.IsSignaled(); }
36
37 private:
38 void Run() override {
39 tracker_->Shutdown();
40 has_returned_.Signal();
41 }
42
43 TaskTracker* const tracker_;
44 WaitableEvent has_returned_;
45
46 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
47 };
48
49 // Runs a task asynchronously.
50 class ThreadRunningTask : public SimpleThread {
51 public:
52 explicit ThreadRunningTask(TaskTracker* tracker, const Task* task)
53 : SimpleThread("ThreadRunningTask"), tracker_(tracker), task_(task) {}
54
55 private:
56 void Run() override { tracker_->RunTask(task_); }
57
58 TaskTracker* const tracker_;
59 const Task* const task_;
60
61 DISALLOW_COPY_AND_ASSIGN(ThreadRunningTask);
62 };
63
64 class TaskSchedulerTaskTrackerTest
65 : public testing::TestWithParam<TaskShutdownBehavior> {
66 protected:
67 TaskSchedulerTaskTrackerTest() = default;
68
69 // Creates a task with |shutdown_behavior|.
70 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) {
71 return make_scoped_ptr(new Task(
72 FROM_HERE,
73 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
74 TaskTraits().WithShutdownBehavior(shutdown_behavior)));
75 }
76
77 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation,
78 // |task| is added to |posted_tasks_|.
79 void PostTaskViaTracker(scoped_ptr<Task> task) {
80 tracker_.PostTask(
81 Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, Unretained(this)),
82 std::move(task));
83 }
84
85 // Tries to run the next task in |posted_tasks_| via |tracker_|.
86 void RunNextPostedTaskViaTracker() {
87 ASSERT_FALSE(posted_tasks_.empty());
88 tracker_.RunTask(posted_tasks_.front().get());
89 posted_tasks_.pop();
90 }
91
92 // Calls tracker_->Shutdown() on a new thread. When this returns, Shutdown()
93 // method has been entered on the new thread, but it hasn't necessarily
94 // returned.
95 void CallShutdownAsync() {
96 ASSERT_FALSE(thread_calling_shutdown_);
97 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_));
98 thread_calling_shutdown_->Start();
99 while (!tracker_.IsShuttingDownForTesting() &&
100 !tracker_.shutdown_completed()) {
101 PlatformThread::YieldCurrentThread();
102 }
103 }
104
105 void WaitForAsyncShutdownCompleted() {
106 ASSERT_TRUE(thread_calling_shutdown_);
107 thread_calling_shutdown_->Join();
108 EXPECT_TRUE(thread_calling_shutdown_->has_returned());
109 EXPECT_TRUE(tracker_.shutdown_completed());
110 }
111
112 void VerifyAsyncShutdownInProgress() {
113 ASSERT_TRUE(thread_calling_shutdown_);
114 EXPECT_FALSE(thread_calling_shutdown_->has_returned());
115 EXPECT_FALSE(tracker_.shutdown_completed());
116 EXPECT_TRUE(tracker_.IsShuttingDownForTesting());
117 }
118
119 TaskTracker tracker_;
120 size_t num_tasks_executed_ = 0;
121 std::queue<scoped_ptr<Task>> posted_tasks_;
122
123 private:
124 void PostTaskCallback(scoped_ptr<Task> task) {
125 posted_tasks_.push(std::move(task));
126 }
127
128 void RunTaskCallback() { ++num_tasks_executed_; }
129
130 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
131
132 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
133 };
134
135 #define WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED() \
136 do { \
137 SCOPED_TRACE(""); \
138 WaitForAsyncShutdownCompleted(); \
139 } while (false)
140
141 #define VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS() \
142 do { \
143 SCOPED_TRACE(""); \
144 VerifyAsyncShutdownInProgress(); \
145 } while (false)
146
147 } // namespace
148
149 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown) {
150 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
151 const Task* task_to_post_raw = task_to_post.get();
152
153 // Post the task.
154 EXPECT_TRUE(posted_tasks_.empty());
155 PostTaskViaTracker(std::move(task_to_post));
156 EXPECT_EQ(1U, posted_tasks_.size());
157 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
158
159 // Run the posted task.
160 EXPECT_EQ(0U, num_tasks_executed_);
161 RunNextPostedTaskViaTracker();
162 EXPECT_EQ(1U, num_tasks_executed_);
163
164 // Shutdown() shouldn't block.
165 tracker_.Shutdown();
166 }
167
168 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunLongTaskBeforeShutdown) {
169 // Post a task that will block until |event| is signaled.
170 EXPECT_TRUE(posted_tasks_.empty());
171 WaitableEvent event(false, false);
172 PostTaskViaTracker(make_scoped_ptr(
173 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
174 TaskTraits().WithShutdownBehavior(GetParam()))));
175 EXPECT_EQ(1U, posted_tasks_.size());
176
177 // Run the task asynchronouly.
178 ThreadRunningTask thread_running_task(&tracker_, posted_tasks_.front().get());
179 thread_running_task.Start();
180
181 // Initiate shutdown while the task is running.
182 CallShutdownAsync();
183
184 if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) {
185 // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress.
186 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
187 } else {
188 // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress.
189 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
190 }
191
192 // Unblock the task.
193 event.Signal();
194 thread_running_task.Join();
195
196 // Shutdown should now complete for a non CONTINUE_ON_SHUTDOWN task.
197 if (GetParam() != TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)
198 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
199 }
200
201 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunDuringShutdown) {
202 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
203 const Task* task_to_post_raw = task_to_post.get();
204
205 // Post the task.
206 EXPECT_TRUE(posted_tasks_.empty());
207 PostTaskViaTracker(std::move(task_to_post));
208 EXPECT_EQ(1U, posted_tasks_.size());
209 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
210
211 // Post a BLOCK_SHUTDOWN task just to block shutdown.
212 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
213
214 // Call Shutdown() asynchronously.
215 CallShutdownAsync();
216 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
217
218 // Try to run the first posted task. Only BLOCK_SHUTDOWN tasks should run,
219 // others should be discarded.
220 EXPECT_EQ(0U, num_tasks_executed_);
221 RunNextPostedTaskViaTracker();
222 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 1U : 0U,
223 num_tasks_executed_);
224 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
225
226 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task.
227 RunNextPostedTaskViaTracker();
228 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
229 num_tasks_executed_);
230 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
231 }
232
233 TEST_P(TaskSchedulerTaskTrackerTest, PostBeforeShutdownRunAfterShutdown) {
234 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
235 const Task* task_to_post_raw = task_to_post.get();
236
237 // Post the task.
238 EXPECT_TRUE(posted_tasks_.empty());
239 PostTaskViaTracker(std::move(task_to_post));
240 EXPECT_EQ(1U, posted_tasks_.size());
241 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
242
243 // Call Shutdown() asynchronously.
244 CallShutdownAsync();
245 EXPECT_EQ(0U, num_tasks_executed_);
246
247 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
248 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
249
250 // Run the task to unblock shutdown.
251 RunNextPostedTaskViaTracker();
252 EXPECT_EQ(1U, num_tasks_executed_);
253 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
254
255 // It is not possible to test running a BLOCK_SHUTDOWN task posted before
256 // shutdown after shutdown because Shutdown() won't return if there are
257 // pending BLOCK_SHUTDOWN tasks.
258 } else {
259 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
260
261 // The task shouldn't be allowed to run after shutdown.
262 RunNextPostedTaskViaTracker();
263 EXPECT_EQ(0U, num_tasks_executed_);
264 }
265 }
266
267 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown) {
268 // Post a BLOCK_SHUTDOWN task just to block shutdown.
269 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
270 scoped_ptr<Task> block_shutdown_task = std::move(posted_tasks_.front());
271 posted_tasks_.pop();
272
273 // Call Shutdown() asynchronously.
274 CallShutdownAsync();
275 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
276
277 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
278 // Post a BLOCK_SHUTDOWN task. This should succeed.
279 EXPECT_TRUE(posted_tasks_.empty());
280 PostTaskViaTracker(CreateTask(GetParam()));
281 EXPECT_EQ(1U, posted_tasks_.size());
282
283 // Run the BLOCK_SHUTDOWN task. This should succeed.
284 EXPECT_EQ(0U, num_tasks_executed_);
285 RunNextPostedTaskViaTracker();
286 EXPECT_EQ(1U, num_tasks_executed_);
287 } else {
288 // It shouldn't be possible to post a non BLOCK_SHUTDOWN task.
289 PostTaskViaTracker(CreateTask(GetParam()));
290 EXPECT_TRUE(posted_tasks_.empty());
291
292 // Don't try to run the task, because it hasn't been posted successfully.
293 }
294
295 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
296 // of the test.
297 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS();
298 tracker_.RunTask(block_shutdown_task.get());
299 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U,
300 num_tasks_executed_);
301 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
302 }
303
304 TEST_P(TaskSchedulerTaskTrackerTest, PostAfterShutdown) {
305 // It is not possible to post a task after shutdown.
306 tracker_.Shutdown();
307 EXPECT_TRUE(posted_tasks_.empty());
308
309 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) {
310 EXPECT_DCHECK_DEATH({ PostTaskViaTracker(CreateTask(GetParam())); }, "");
311 } else {
312 PostTaskViaTracker(CreateTask(GetParam()));
313 }
314
315 EXPECT_TRUE(posted_tasks_.empty());
316 }
317
318 INSTANTIATE_TEST_CASE_P(
319 ContinueOnShutdown,
320 TaskSchedulerTaskTrackerTest,
321 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
322 INSTANTIATE_TEST_CASE_P(
323 SkipOnShutdown,
324 TaskSchedulerTaskTrackerTest,
325 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
326 INSTANTIATE_TEST_CASE_P(
327 BlockShutdown,
328 TaskSchedulerTaskTrackerTest,
329 ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN));
330
331 } // namespace internal
332 } // namespace base
OLDNEW
« no previous file with comments | « base/task_scheduler/task_tracker.cc ('k') | base/task_scheduler/task_traits.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698