• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "base/task_scheduler/lazy_task_runner.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/sequence_checker_impl.h"
10 #include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h"
11 #include "base/test/scoped_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 defined(OS_WIN)
17 #include "base/win/com_init_util.h"
18 #endif
19 
20 namespace base {
21 
22 namespace {
23 
24 LazySequencedTaskRunner g_sequenced_task_runner_user_visible =
25     LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_VISIBLE});
26 LazySequencedTaskRunner g_sequenced_task_runner_user_blocking =
27     LAZY_SEQUENCED_TASK_RUNNER_INITIALIZER({TaskPriority::USER_BLOCKING});
28 
29 LazySingleThreadTaskRunner g_single_thread_task_runner_user_visible =
30     LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
31         {TaskPriority::USER_VISIBLE},
32         SingleThreadTaskRunnerThreadMode::SHARED);
33 LazySingleThreadTaskRunner g_single_thread_task_runner_user_blocking =
34     LAZY_SINGLE_THREAD_TASK_RUNNER_INITIALIZER(
35         {TaskPriority::USER_BLOCKING},
36         SingleThreadTaskRunnerThreadMode::SHARED);
37 
38 #if defined(OS_WIN)
39 LazyCOMSTATaskRunner g_com_sta_task_runner_user_visible =
40     LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
41         {TaskPriority::USER_VISIBLE},
42         SingleThreadTaskRunnerThreadMode::SHARED);
43 LazyCOMSTATaskRunner g_com_sta_task_runner_user_blocking =
44     LAZY_COM_STA_TASK_RUNNER_INITIALIZER(
45         {TaskPriority::USER_BLOCKING},
46         SingleThreadTaskRunnerThreadMode::SHARED);
47 #endif  // defined(OS_WIN)
48 
InitCheckers(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker)49 void InitCheckers(SequenceCheckerImpl* sequence_checker,
50                   ThreadCheckerImpl* thread_checker) {
51   sequence_checker->DetachFromSequence();
52   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
53   thread_checker->DetachFromThread();
54   EXPECT_TRUE(thread_checker->CalledOnValidThread());
55 }
56 
ExpectSequencedEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority)57 void ExpectSequencedEnvironment(SequenceCheckerImpl* sequence_checker,
58                                 ThreadCheckerImpl* thread_checker,
59                                 TaskPriority expected_priority) {
60   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
61   EXPECT_FALSE(thread_checker->CalledOnValidThread());
62   EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
63 }
64 
ExpectSingleThreadEnvironment(SequenceCheckerImpl * sequence_checker,ThreadCheckerImpl * thread_checker,TaskPriority expected_priority,bool expect_com_sta=false)65 void ExpectSingleThreadEnvironment(SequenceCheckerImpl* sequence_checker,
66                                    ThreadCheckerImpl* thread_checker,
67                                    TaskPriority expected_priority
68 #if defined(OS_WIN)
69                                    ,
70                                    bool expect_com_sta = false
71 #endif
72                                    ) {
73   EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
74   EXPECT_TRUE(thread_checker->CalledOnValidThread());
75   EXPECT_EQ(expected_priority, internal::GetTaskPriorityForCurrentThread());
76 
77 #if defined(OS_WIN)
78   if (expect_com_sta)
79     win::AssertComApartmentType(win::ComApartmentType::STA);
80 #endif
81 }
82 
83 class TaskSchedulerLazyTaskRunnerEnvironmentTest : public testing::Test {
84  protected:
85   TaskSchedulerLazyTaskRunnerEnvironmentTest() = default;
86 
TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,bool expect_single_thread,TaskPriority expected_priority,bool expect_com_sta=false)87   void TestTaskRunnerEnvironment(scoped_refptr<SequencedTaskRunner> task_runner,
88                                  bool expect_single_thread,
89                                  TaskPriority expected_priority
90 #if defined(OS_WIN)
91                                  ,
92                                  bool expect_com_sta = false
93 #endif
94                                  ) {
95     SequenceCheckerImpl sequence_checker;
96     ThreadCheckerImpl thread_checker;
97     task_runner->PostTask(FROM_HERE,
98                           BindOnce(&InitCheckers, Unretained(&sequence_checker),
99                                    Unretained(&thread_checker)));
100     scoped_task_environment_.RunUntilIdle();
101 
102     OnceClosure task =
103         expect_single_thread
104             ? BindOnce(&ExpectSingleThreadEnvironment,
105                        Unretained(&sequence_checker),
106                        Unretained(&thread_checker), expected_priority
107 #if defined(OS_WIN)
108                        ,
109                        expect_com_sta
110 #endif
111                        )
112             : BindOnce(&ExpectSequencedEnvironment,
113                        Unretained(&sequence_checker),
114                        Unretained(&thread_checker), expected_priority);
115     task_runner->PostTask(FROM_HERE, std::move(task));
116     scoped_task_environment_.RunUntilIdle();
117   }
118 
119   test::ScopedTaskEnvironment scoped_task_environment_;
120 
121  private:
122   DISALLOW_COPY_AND_ASSIGN(TaskSchedulerLazyTaskRunnerEnvironmentTest);
123 };
124 
125 }  // namespace
126 
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySequencedTaskRunnerUserVisible)127 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
128        LazySequencedTaskRunnerUserVisible) {
129   TestTaskRunnerEnvironment(g_sequenced_task_runner_user_visible.Get(), false,
130                             TaskPriority::USER_VISIBLE);
131 }
132 
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySequencedTaskRunnerUserBlocking)133 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
134        LazySequencedTaskRunnerUserBlocking) {
135   TestTaskRunnerEnvironment(g_sequenced_task_runner_user_blocking.Get(), false,
136                             TaskPriority::USER_BLOCKING);
137 }
138 
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySingleThreadTaskRunnerUserVisible)139 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
140        LazySingleThreadTaskRunnerUserVisible) {
141   TestTaskRunnerEnvironment(g_single_thread_task_runner_user_visible.Get(),
142                             true, TaskPriority::USER_VISIBLE);
143 }
144 
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazySingleThreadTaskRunnerUserBlocking)145 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
146        LazySingleThreadTaskRunnerUserBlocking) {
147   TestTaskRunnerEnvironment(g_single_thread_task_runner_user_blocking.Get(),
148                             true, TaskPriority::USER_BLOCKING);
149 }
150 
151 #if defined(OS_WIN)
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazyCOMSTATaskRunnerUserVisible)152 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
153        LazyCOMSTATaskRunnerUserVisible) {
154   TestTaskRunnerEnvironment(g_com_sta_task_runner_user_visible.Get(), true,
155                             TaskPriority::USER_VISIBLE, true);
156 }
157 
TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,LazyCOMSTATaskRunnerUserBlocking)158 TEST_F(TaskSchedulerLazyTaskRunnerEnvironmentTest,
159        LazyCOMSTATaskRunnerUserBlocking) {
160   TestTaskRunnerEnvironment(g_com_sta_task_runner_user_blocking.Get(), true,
161                             TaskPriority::USER_BLOCKING, true);
162 }
163 #endif  // defined(OS_WIN)
164 
TEST(TaskSchdulerLazyTaskRunnerTest,LazySequencedTaskRunnerReset)165 TEST(TaskSchdulerLazyTaskRunnerTest, LazySequencedTaskRunnerReset) {
166   for (int i = 0; i < 2; ++i) {
167     test::ScopedTaskEnvironment scoped_task_environment;
168     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
169     // goes out of scope, the second invocation of the line below will access a
170     // deleted TaskScheduler and crash.
171     g_sequenced_task_runner_user_visible.Get()->PostTask(FROM_HERE,
172                                                          DoNothing());
173   }
174 }
175 
TEST(TaskSchdulerLazyTaskRunnerTest,LazySingleThreadTaskRunnerReset)176 TEST(TaskSchdulerLazyTaskRunnerTest, LazySingleThreadTaskRunnerReset) {
177   for (int i = 0; i < 2; ++i) {
178     test::ScopedTaskEnvironment scoped_task_environment;
179     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
180     // goes out of scope, the second invocation of the line below will access a
181     // deleted TaskScheduler and crash.
182     g_single_thread_task_runner_user_visible.Get()->PostTask(FROM_HERE,
183                                                              DoNothing());
184   }
185 }
186 
187 #if defined(OS_WIN)
TEST(TaskSchdulerLazyTaskRunnerTest,LazyCOMSTATaskRunnerReset)188 TEST(TaskSchdulerLazyTaskRunnerTest, LazyCOMSTATaskRunnerReset) {
189   for (int i = 0; i < 2; ++i) {
190     test::ScopedTaskEnvironment scoped_task_environment;
191     // If the TaskRunner isn't released when the test::ScopedTaskEnvironment
192     // goes out of scope, the second invocation of the line below will access a
193     // deleted TaskScheduler and crash.
194     g_com_sta_task_runner_user_visible.Get()->PostTask(FROM_HERE, DoNothing());
195   }
196 }
197 #endif  // defined(OS_WIN)
198 
199 }  // namespace base
200