OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/scheduler_single_thread_task_runner_manager.h" | 5 #include "base/task_scheduler/scheduler_single_thread_task_runner_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/synchronization/lock.h" | 9 #include "base/synchronization/lock.h" |
10 #include "base/synchronization/waitable_event.h" | 10 #include "base/synchronization/waitable_event.h" |
11 #include "base/task_scheduler/delayed_task_manager.h" | 11 #include "base/task_scheduler/delayed_task_manager.h" |
12 #include "base/task_scheduler/post_task.h" | 12 #include "base/task_scheduler/post_task.h" |
13 #include "base/task_scheduler/scheduler_worker_pool_params.h" | 13 #include "base/task_scheduler/scheduler_worker_pool_params.h" |
14 #include "base/task_scheduler/task_tracker.h" | 14 #include "base/task_scheduler/task_tracker.h" |
15 #include "base/task_scheduler/task_traits.h" | 15 #include "base/task_scheduler/task_traits.h" |
16 #include "base/test/test_timeouts.h" | 16 #include "base/test/test_timeouts.h" |
17 #include "base/threading/simple_thread.h" | |
17 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
19 | 20 |
20 namespace base { | 21 namespace base { |
21 namespace internal { | 22 namespace internal { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 enum WorkerPoolType { | 26 enum WorkerPoolType : size_t { |
26 BACKGROUND_WORKER_POOL = 0, | 27 BACKGROUND_WORKER_POOL = 0, |
27 FOREGROUND_WORKER_POOL, | 28 FOREGROUND_WORKER_POOL, |
28 }; | 29 }; |
29 | 30 |
30 static size_t GetThreadPoolIndexForTraits(const TaskTraits& traits) { | 31 static size_t GetThreadPoolIndexForTraits(const TaskTraits& traits) { |
31 return traits.priority() == TaskPriority::BACKGROUND ? BACKGROUND_WORKER_POOL | 32 return traits.priority() == TaskPriority::BACKGROUND ? BACKGROUND_WORKER_POOL |
32 : FOREGROUND_WORKER_POOL; | 33 : FOREGROUND_WORKER_POOL; |
33 } | 34 } |
34 | 35 |
36 std::vector<SchedulerWorkerPoolParams> GetParamsVector() { | |
37 using StandbyThreadPolicy = SchedulerWorkerPoolParams::StandbyThreadPolicy; | |
38 | |
39 std::vector<SchedulerWorkerPoolParams> params_vector; | |
40 | |
41 DCHECK_EQ(BACKGROUND_WORKER_POOL, params_vector.size()); | |
42 params_vector.emplace_back("Background", ThreadPriority::BACKGROUND, | |
43 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); | |
44 | |
45 DCHECK_EQ(FOREGROUND_WORKER_POOL, params_vector.size()); | |
gab
2017/03/15 20:00:13
EXPECT_EQ instead of DCHECK_EQ in tests.
robliao
2017/03/15 20:40:16
I would prefer to fail fast here since there's no
| |
46 params_vector.emplace_back("Foreground", ThreadPriority::NORMAL, | |
47 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); | |
48 | |
49 return params_vector; | |
50 } | |
51 | |
35 class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test { | 52 class TaskSchedulerSingleThreadTaskRunnerManagerTest : public testing::Test { |
36 public: | 53 public: |
37 TaskSchedulerSingleThreadTaskRunnerManagerTest() | 54 TaskSchedulerSingleThreadTaskRunnerManagerTest() |
38 : service_thread_("TaskSchedulerServiceThread") {} | 55 : service_thread_("TaskSchedulerServiceThread") {} |
39 | 56 |
40 void SetUp() override { | 57 void SetUp() override { |
41 service_thread_.Start(); | 58 service_thread_.Start(); |
42 | 59 |
43 using StandbyThreadPolicy = SchedulerWorkerPoolParams::StandbyThreadPolicy; | |
44 | |
45 std::vector<SchedulerWorkerPoolParams> params_vector; | |
46 | |
47 ASSERT_EQ(BACKGROUND_WORKER_POOL, params_vector.size()); | |
48 params_vector.emplace_back("Background", ThreadPriority::BACKGROUND, | |
49 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); | |
50 | |
51 ASSERT_EQ(FOREGROUND_WORKER_POOL, params_vector.size()); | |
52 params_vector.emplace_back("Foreground", ThreadPriority::NORMAL, | |
53 StandbyThreadPolicy::LAZY, 1U, TimeDelta::Max()); | |
54 | |
55 delayed_task_manager_ = | 60 delayed_task_manager_ = |
56 MakeUnique<DelayedTaskManager>(service_thread_.task_runner()); | 61 MakeUnique<DelayedTaskManager>(service_thread_.task_runner()); |
57 single_thread_task_runner_manager_ = | 62 single_thread_task_runner_manager_ = |
58 MakeUnique<SchedulerSingleThreadTaskRunnerManager>( | 63 MakeUnique<SchedulerSingleThreadTaskRunnerManager>( |
59 params_vector, Bind(&GetThreadPoolIndexForTraits), &task_tracker_, | 64 GetParamsVector(), Bind(&GetThreadPoolIndexForTraits), |
60 delayed_task_manager_.get()); | 65 &task_tracker_, delayed_task_manager_.get()); |
61 } | 66 } |
62 | 67 |
63 void TearDown() override { | 68 void TearDown() override { |
64 single_thread_task_runner_manager_->JoinForTesting(); | 69 TearDownSingleThreadTaskRunnerManager(); |
65 single_thread_task_runner_manager_.reset(); | |
66 delayed_task_manager_.reset(); | 70 delayed_task_manager_.reset(); |
67 service_thread_.Stop(); | 71 service_thread_.Stop(); |
68 } | 72 } |
69 | 73 |
70 protected: | 74 protected: |
75 virtual void TearDownSingleThreadTaskRunnerManager() { | |
gab
2017/03/15 20:00:13
Instead of having this virtual method simply to sk
robliao
2017/03/15 20:40:16
That seemed pretty subtle.
It's nicer when a class
| |
76 single_thread_task_runner_manager_->JoinForTesting(); | |
77 single_thread_task_runner_manager_.reset(); | |
78 } | |
79 | |
71 std::unique_ptr<SchedulerSingleThreadTaskRunnerManager> | 80 std::unique_ptr<SchedulerSingleThreadTaskRunnerManager> |
72 single_thread_task_runner_manager_; | 81 single_thread_task_runner_manager_; |
73 TaskTracker task_tracker_; | 82 TaskTracker task_tracker_; |
74 | 83 |
75 private: | 84 private: |
76 Thread service_thread_; | 85 Thread service_thread_; |
77 std::unique_ptr<DelayedTaskManager> delayed_task_manager_; | 86 std::unique_ptr<DelayedTaskManager> delayed_task_manager_; |
78 | 87 |
79 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTest); | 88 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerTest); |
80 }; | 89 }; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1, | 252 [](scoped_refptr<SingleThreadTaskRunner> task_runner_1, |
244 scoped_refptr<SingleThreadTaskRunner> task_runner_2) { | 253 scoped_refptr<SingleThreadTaskRunner> task_runner_2) { |
245 EXPECT_FALSE(task_runner_1->RunsTasksOnCurrentThread()); | 254 EXPECT_FALSE(task_runner_1->RunsTasksOnCurrentThread()); |
246 EXPECT_TRUE(task_runner_2->RunsTasksOnCurrentThread()); | 255 EXPECT_TRUE(task_runner_2->RunsTasksOnCurrentThread()); |
247 }, | 256 }, |
248 task_runner_1, task_runner_2)); | 257 task_runner_1, task_runner_2)); |
249 | 258 |
250 task_tracker_.Shutdown(); | 259 task_tracker_.Shutdown(); |
251 } | 260 } |
252 | 261 |
262 namespace { | |
263 | |
264 class CallJoinFromDifferentThread : public SimpleThread { | |
265 public: | |
266 CallJoinFromDifferentThread( | |
267 SchedulerSingleThreadTaskRunnerManager* manager_to_join) | |
268 : SimpleThread("SchedulerSingleThreadTaskRunnerManagerJoinThread"), | |
269 manager_to_join_(manager_to_join), | |
270 run_started_event_(WaitableEvent::ResetPolicy::MANUAL, | |
271 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
272 | |
273 ~CallJoinFromDifferentThread() override = default; | |
274 | |
275 void Run() override { | |
276 run_started_event_.Signal(); | |
277 manager_to_join_->JoinForTesting(); | |
278 } | |
279 | |
280 void WaitForRunToStart() { run_started_event_.Wait(); } | |
281 | |
282 private: | |
283 SchedulerSingleThreadTaskRunnerManager* const manager_to_join_; | |
284 WaitableEvent run_started_event_; | |
285 DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread); | |
gab
2017/03/15 20:00:13
empty line before DISALLOW...() macro
robliao
2017/03/15 20:40:16
Done.
| |
286 }; | |
287 | |
288 class TaskSchedulerSingleThreadTaskRunnerManagerJoinTest | |
289 : public TaskSchedulerSingleThreadTaskRunnerManagerTest { | |
290 public: | |
291 TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() = default; | |
292 ~TaskSchedulerSingleThreadTaskRunnerManagerJoinTest() override = default; | |
293 | |
294 protected: | |
295 void TearDownSingleThreadTaskRunnerManager() override { | |
296 // The tests themselves are responsible for calling JoinForTesting(). | |
297 single_thread_task_runner_manager_.reset(); | |
298 } | |
299 | |
300 private: | |
301 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest); | |
302 }; | |
303 | |
304 } // namespace | |
305 | |
306 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, ConcurrentJoin) { | |
gab
2017/03/15 20:00:13
How is concurrent join stressing the code added in
robliao
2017/03/15 20:40:16
Added a comment. Both of these tests cause two dif
| |
307 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, | |
308 WaitableEvent::InitialState::NOT_SIGNALED); | |
309 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, | |
310 WaitableEvent::InitialState::NOT_SIGNALED); | |
311 | |
312 { | |
313 auto task_runner = single_thread_task_runner_manager_ | |
314 ->CreateSingleThreadTaskRunnerWithTraits( | |
315 TaskTraits().WithBaseSyncPrimitives()); | |
316 EXPECT_TRUE(task_runner->PostTask( | |
317 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); | |
318 EXPECT_TRUE(task_runner->PostTask( | |
319 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); | |
320 } | |
321 | |
322 task_running.Wait(); | |
323 CallJoinFromDifferentThread join_from_different_thread( | |
324 single_thread_task_runner_manager_.get()); | |
325 join_from_different_thread.Start(); | |
326 join_from_different_thread.WaitForRunToStart(); | |
327 task_blocking.Signal(); | |
328 join_from_different_thread.Join(); | |
329 } | |
330 | |
331 TEST_F(TaskSchedulerSingleThreadTaskRunnerManagerJoinTest, | |
332 ConcurrentJoinExtraSkippedTask) { | |
gab
2017/03/15 20:00:13
And how is this one different? Please document wha
robliao
2017/03/15 20:40:16
Added a comment.
// Tests to make sure that task
| |
333 WaitableEvent task_running(WaitableEvent::ResetPolicy::MANUAL, | |
334 WaitableEvent::InitialState::NOT_SIGNALED); | |
335 WaitableEvent task_blocking(WaitableEvent::ResetPolicy::MANUAL, | |
336 WaitableEvent::InitialState::NOT_SIGNALED); | |
337 | |
338 { | |
339 auto task_runner = single_thread_task_runner_manager_ | |
340 ->CreateSingleThreadTaskRunnerWithTraits( | |
341 TaskTraits().WithBaseSyncPrimitives()); | |
342 EXPECT_TRUE(task_runner->PostTask( | |
343 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&task_running)))); | |
344 EXPECT_TRUE(task_runner->PostTask( | |
345 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&task_blocking)))); | |
346 EXPECT_TRUE(task_runner->PostTask(FROM_HERE, Bind(&DoNothing))); | |
347 } | |
348 | |
349 task_running.Wait(); | |
350 CallJoinFromDifferentThread join_from_different_thread( | |
351 single_thread_task_runner_manager_.get()); | |
352 join_from_different_thread.Start(); | |
353 join_from_different_thread.WaitForRunToStart(); | |
354 task_blocking.Signal(); | |
355 join_from_different_thread.Join(); | |
356 } | |
357 | |
253 } // namespace internal | 358 } // namespace internal |
254 } // namespace base | 359 } // namespace base |
OLD | NEW |