• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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/threading/scoped_thread_priority.h"
6 
7 #include "base/test/gtest_util.h"
8 #include "base/threading/platform_thread.h"
9 #include "base/threading/thread.h"
10 #include "build/build_config.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace base {
14 
15 namespace {
16 
17 // Tests in this file invoke an API that tracks state in static variable. They
18 // can therefore only be invoked once per process.
19 #define ASSERT_RUNS_ONCE()                                              \
20   static int num_times_run = 0;                                         \
21   ++num_times_run;                                                      \
22   if (num_times_run > 1)                                                \
23     ADD_FAILURE() << "This test cannot run multiple times in the same " \
24                      "process.";
25 
26 static ThreadType kAllThreadTypes[] = {
27     ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
28     ThreadType::kDefault, ThreadType::kBackground};
29 
30 static_assert(static_cast<int>(ThreadType::kBackground) == 0,
31               "kBackground isn't lowest");
32 static_assert(ThreadType::kRealtimeAudio == ThreadType::kMaxValue,
33               "kRealtimeAudio isn't highest");
34 
35 class ScopedThreadPriorityTest : public testing::Test {
36  protected:
SetUp()37   void SetUp() override {
38     // Ensures the default thread priority is set.
39     PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
40     ASSERT_EQ(ThreadPriorityForTest::kNormal,
41               PlatformThread::GetCurrentThreadPriorityForTest());
42   }
43 };
44 
45 using ScopedThreadPriorityDeathTest = ScopedThreadPriorityTest;
46 
47 #if BUILDFLAG(IS_WIN)
FunctionThatBoostsPriorityOnFirstInvoke(ThreadPriorityForTest expected_priority)48 void FunctionThatBoostsPriorityOnFirstInvoke(
49     ThreadPriorityForTest expected_priority) {
50   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
51   EXPECT_EQ(expected_priority,
52             PlatformThread::GetCurrentThreadPriorityForTest());
53 }
54 
FunctionThatBoostsPriorityOnEveryInvoke()55 void FunctionThatBoostsPriorityOnEveryInvoke() {
56   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
57   EXPECT_EQ(base::ThreadPriorityForTest::kNormal,
58             PlatformThread::GetCurrentThreadPriorityForTest());
59 }
60 
61 #endif  // BUILDFLAG(IS_WIN)
62 
63 }  // namespace
64 
TEST_F(ScopedThreadPriorityTest,BasicTest)65 TEST_F(ScopedThreadPriorityTest, BasicTest) {
66   for (auto from : kAllThreadTypes) {
67     if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from))
68       continue;
69     for (auto to : kAllThreadTypes) {
70       // ThreadType::kRealtimeAudio is not a valid |target_thread_type| for
71       // ScopedBoostPriority.
72       if (to == ThreadType::kRealtimeAudio)
73         continue;
74       Thread thread("ScopedThreadPriorityTest");
75       thread.StartWithOptions(Thread::Options(from));
76       thread.WaitUntilThreadStarted();
77       thread.task_runner()->PostTask(
78           FROM_HERE,
79           BindOnce(
80               [](ThreadType from, ThreadType to) {
81                 EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
82                 {
83                   ScopedBoostPriority scoped_boost_priority(to);
84                   bool will_boost_priority =
85                       from < to &&
86                       PlatformThread::CanChangeThreadType(from, to) &&
87                       PlatformThread::CanChangeThreadType(to, from);
88                   EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
89                             will_boost_priority ? to : from);
90                 }
91                 EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
92               },
93               from, to));
94     }
95   }
96 }
97 
TEST_F(ScopedThreadPriorityDeathTest,NoRealTime)98 TEST_F(ScopedThreadPriorityDeathTest, NoRealTime) {
99   EXPECT_DCHECK_DEATH({
100     ScopedBoostPriority scoped_boost_priority(ThreadType::kRealtimeAudio);
101   });
102 }
103 
TEST_F(ScopedThreadPriorityTest,WithoutPriorityBoost)104 TEST_F(ScopedThreadPriorityTest, WithoutPriorityBoost) {
105   ASSERT_RUNS_ONCE();
106 
107   // Validates that a thread at normal priority keep the same priority.
108   {
109     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
110     EXPECT_EQ(ThreadPriorityForTest::kNormal,
111               PlatformThread::GetCurrentThreadPriorityForTest());
112   }
113   EXPECT_EQ(ThreadPriorityForTest::kNormal,
114             PlatformThread::GetCurrentThreadPriorityForTest());
115 }
116 
117 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,WithPriorityBoost)118 TEST_F(ScopedThreadPriorityTest, WithPriorityBoost) {
119   ASSERT_RUNS_ONCE();
120 
121   // Validates that a thread at background priority is boosted to normal
122   // priority.
123   PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
124   {
125     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
126     EXPECT_EQ(ThreadPriorityForTest::kNormal,
127               PlatformThread::GetCurrentThreadPriorityForTest());
128   }
129   EXPECT_EQ(ThreadPriorityForTest::kBackground,
130             PlatformThread::GetCurrentThreadPriorityForTest());
131 
132   // Put back the default thread priority.
133   PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
134 }
135 #endif  // BUILDFLAG(IS_WIN)
136 
137 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,NestedScope)138 TEST_F(ScopedThreadPriorityTest, NestedScope) {
139   ASSERT_RUNS_ONCE();
140 
141   PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
142 
143   {
144     SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
145     EXPECT_EQ(ThreadPriorityForTest::kNormal,
146               PlatformThread::GetCurrentThreadPriorityForTest());
147     {
148       SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
149       EXPECT_EQ(ThreadPriorityForTest::kNormal,
150                 PlatformThread::GetCurrentThreadPriorityForTest());
151     }
152     EXPECT_EQ(ThreadPriorityForTest::kNormal,
153               PlatformThread::GetCurrentThreadPriorityForTest());
154   }
155 
156   EXPECT_EQ(ThreadPriorityForTest::kBackground,
157             PlatformThread::GetCurrentThreadPriorityForTest());
158 
159   // Put back the default thread priority.
160   PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
161 }
162 #endif  // BUILDFLAG(IS_WIN)
163 
164 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,FunctionThatBoostsPriorityOnFirstInvoke)165 TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnFirstInvoke) {
166   ASSERT_RUNS_ONCE();
167 
168   PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
169 
170   FunctionThatBoostsPriorityOnFirstInvoke(base::ThreadPriorityForTest::kNormal);
171   FunctionThatBoostsPriorityOnFirstInvoke(
172       base::ThreadPriorityForTest::kBackground);
173 
174   // Put back the default thread priority.
175   PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
176 }
177 
TEST_F(ScopedThreadPriorityTest,FunctionThatBoostsPriorityOnEveryInvoke)178 TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnEveryInvoke) {
179   PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
180 
181   FunctionThatBoostsPriorityOnEveryInvoke();
182   FunctionThatBoostsPriorityOnEveryInvoke();
183 
184   // Put back the default thread priority.
185   PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
186 }
187 
188 #endif  // BUILDFLAG(IS_WIN)
189 
190 }  // namespace base
191