1 // Copyright 2017 The Chromium Authors
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/lazy_thread_pool_task_runner.h"
6
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/sequence_checker_impl.h"
10 #include "base/task/scoped_set_task_priority_for_current_thread.h"
11 #include "base/test/task_environment.h"
12 #include "base/threading/thread_checker_impl.h"
13 #include "build/build_config.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #if BUILDFLAG(IS_WIN)
17 #include "base/win/com_init_util.h"
18 #endif
19
20 namespace base {
21
22 namespace {
23
24 LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner_user_visible =
25 LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
26 TaskTraits(TaskPriority::USER_VISIBLE));
27 LazyThreadPoolSequencedTaskRunner g_sequenced_task_runner_user_blocking =
28 LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
29 TaskTraits(TaskPriority::USER_BLOCKING));
30
31 LazyThreadPoolSingleThreadTaskRunner g_single_thread_task_runner_user_visible =
32 LAZY_THREAD_POOL_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
33 TaskTraits(TaskPriority::USER_VISIBLE),
34 SingleThreadTaskRunnerThreadMode::SHARED);
35 LazyThreadPoolSingleThreadTaskRunner g_single_thread_task_runner_user_blocking =
36 LAZY_THREAD_POOL_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
37 TaskTraits(TaskPriority::USER_BLOCKING),
38 SingleThreadTaskRunnerThreadMode::SHARED);
39
40 #if BUILDFLAG(IS_WIN)
41 LazyThreadPoolCOMSTATaskRunner g_com_sta_task_runner_user_visible =
42 LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
43 TaskTraits(TaskPriority::USER_VISIBLE),
44 SingleThreadTaskRunnerThreadMode::SHARED);
45 LazyThreadPoolCOMSTATaskRunner g_com_sta_task_runner_user_blocking =
46 LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
47 TaskTraits(TaskPriority::USER_BLOCKING),
48 SingleThreadTaskRunnerThreadMode::SHARED);
49 #endif // BUILDFLAG(IS_WIN)
50
InitCheckers(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker)51 void InitCheckers(SequenceCheckerImpl* sequence_checker,
52 ThreadCheckerImpl* thread_checker) {
53 sequence_checker->DetachFromSequence();
54 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
55 thread_checker->DetachFromThread();
56 EXPECT_TRUE(thread_checker->CalledOnValidThread());
57 }
58
ExpectSequencedEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority)59 void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker,
60 ThreadCheckerImpl* thread_checker,
61 TaskPriority expected_priority) {
62 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
63 EXPECT_FALSE(thread_checker->CalledOnValidThread());
64 EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
65 }
66
ExpectSingleThreadEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority,bool expect_com_sta=false)67 void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker,
68 ThreadCheckerImpl* thread_checker,
69 TaskPriority expected_priority
70 #if BUILDFLAG(IS_WIN)
71 ,
72 bool expect_com_sta = false
73 #endif
74 ) {
75 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
76 EXPECT_TRUE(thread_checker->CalledOnValidThread());
77 EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
78
79 #if BUILDFLAG(IS_WIN)
80 if (expect_com_sta)
81 win::AssertComApartmentType(win::ComApartmentType::STA);
82 #endif
83 }
84
85 class LazyThreadPoolTaskRunnerEnvironmentTest : public testing::Test {
86 public:
87 LazyThreadPoolTaskRunnerEnvironmentTest(
88 const LazyThreadPoolTaskRunnerEnvironmentTest&) = delete;
89 LazyThreadPoolTaskRunnerEnvironmentTest& operator=(
90 const LazyThreadPoolTaskRunnerEnvironmentTest&) = delete;
91
92 protected:
93 LazyThreadPoolTaskRunnerEnvironmentTest() = default;
94
TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,bool expect_single_thread,TaskPriority expected_priority,bool expect_com_sta=false)95 void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,
96 bool expect_single_thread,
97 TaskPriority expected_priority
98 #if BUILDFLAG(IS_WIN)
99 ,
100 bool expect_com_sta = false
101 #endif
102 ) {
103 SequenceCheckerImpl sequence_checker;
104 ThreadCheckerImpl thread_checker;
105 task_runner->PostTask(FROM_HERE,
106 BindOnce(&InitCheckers, Unretained(&sequence_checker),
107 Unretained(&thread_checker)));
108 task_environment_.RunUntilIdle();
109
110 OnceClosure task =
111 expect_single_thread
112 ? BindOnce(&ExpectSingleThreadEnvironment,
113 Unretained(&sequence_checker),
114 Unretained(&thread_checker), expected_priority
115 #if BUILDFLAG(IS_WIN)
116 ,
117 expect_com_sta
118 #endif
119 )
120 : BindOnce(&ExpectSequencedEnvironment,
121 Unretained(&sequence_checker),
122 Unretained(&thread_checker), expected_priority);
123 task_runner->PostTask(FROM_HERE, std::move(task));
124 task_environment_.RunUntilIdle();
125 }
126
127 test::TaskEnvironment task_environment_;
128 };
129
130 } // namespace
131
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolSequencedTaskRunnerUserVisible)132 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
133 LazyThreadPoolSequencedTaskRunnerUserVisible) {
134 TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false,
135 TaskPriority::USER_VISIBLE);
136 }
137
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolSequencedTaskRunnerUserBlocking)138 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
139 LazyThreadPoolSequencedTaskRunnerUserBlocking) {
140 TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false,
141 TaskPriority::USER_BLOCKING);
142 }
143
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolSingleThreadTaskRunnerUserVisible)144 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
145 LazyThreadPoolSingleThreadTaskRunnerUserVisible) {
146 TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(),
147 true, TaskPriority::USER_VISIBLE);
148 }
149
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolSingleThreadTaskRunnerUserBlocking)150 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
151 LazyThreadPoolSingleThreadTaskRunnerUserBlocking) {
152 TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(),
153 true, TaskPriority::USER_BLOCKING);
154 }
155
156 #if BUILDFLAG(IS_WIN)
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolCOMSTATaskRunnerUserVisible)157 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
158 LazyThreadPoolCOMSTATaskRunnerUserVisible) {
159 TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true,
160 TaskPriority::USER_VISIBLE, true);
161 }
162
TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,LazyThreadPoolCOMSTATaskRunnerUserBlocking)163 TEST_F(LazyThreadPoolTaskRunnerEnvironmentTest,
164 LazyThreadPoolCOMSTATaskRunnerUserBlocking) {
165 TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true,
166 TaskPriority::USER_BLOCKING, true);
167 }
168 #endif // BUILDFLAG(IS_WIN)
169
TEST(LazyThreadPoolTaskRunnerTest,LazyThreadPoolSequencedTaskRunnerReset)170 TEST(LazyThreadPoolTaskRunnerTest, LazyThreadPoolSequencedTaskRunnerReset) {
171 for (int i = 0; i < 2; ++i) {
172 test::TaskEnvironment task_environment;
173 // If the TaskRunner isn't released when the test::TaskEnvironment
174 // goes out of scope, the second invocation of the line below will access a
175 // deleted ThreadPoolInstance and crash.
176 g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE,
177 DoNothing());
178 }
179 }
180
TEST(LazyThreadPoolTaskRunnerTest,LazyThreadPoolSingleThreadTaskRunnerReset)181 TEST(LazyThreadPoolTaskRunnerTest, LazyThreadPoolSingleThreadTaskRunnerReset) {
182 for (int i = 0; i < 2; ++i) {
183 test::TaskEnvironment task_environment;
184 // If the TaskRunner isn't released when the test::TaskEnvironment
185 // goes out of scope, the second invocation of the line below will access a
186 // deleted ThreadPoolInstance and crash.
187 g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE,
188 DoNothing());
189 }
190 }
191
192 #if BUILDFLAG(IS_WIN)
TEST(LazyThreadPoolTaskRunnerTest,LazyThreadPoolCOMSTATaskRunnerReset)193 TEST(LazyThreadPoolTaskRunnerTest, LazyThreadPoolCOMSTATaskRunnerReset) {
194 for (int i = 0; i < 2; ++i) {
195 test::TaskEnvironment task_environment;
196 // If the TaskRunner isn't released when the test::TaskEnvironment
197 // goes out of scope, the second invocation of the line below will access a
198 // deleted ThreadPoolInstance and crash.
199 g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing());
200 }
201 }
202 #endif // BUILDFLAG(IS_WIN)
203
204 } // namespace base
205