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