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 ASSERT_EQ(ThreadPriorityForTest::kNormal,
39 PlatformThread::GetCurrentThreadPriorityForTest());
40 }
41 };
42
43 #if BUILDFLAG(IS_WIN)
FunctionThatBoostsPriorityOnFirstInvoke(ThreadPriorityForTest expected_priority)44 void FunctionThatBoostsPriorityOnFirstInvoke(
45 ThreadPriorityForTest expected_priority) {
46 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
47 EXPECT_EQ(expected_priority,
48 PlatformThread::GetCurrentThreadPriorityForTest());
49 }
50
FunctionThatBoostsPriorityOnEveryInvoke()51 void FunctionThatBoostsPriorityOnEveryInvoke() {
52 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
53 EXPECT_EQ(base::ThreadPriorityForTest::kNormal,
54 PlatformThread::GetCurrentThreadPriorityForTest());
55 }
56
57 #endif // BUILDFLAG(IS_WIN)
58
59 } // namespace
60
TEST_F(ScopedThreadPriorityTest,BasicTest)61 TEST_F(ScopedThreadPriorityTest, BasicTest) {
62 for (auto from : kAllThreadTypes) {
63 if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from))
64 continue;
65 for (auto to : kAllThreadTypes) {
66 // ThreadType::kRealtimeAudio is not a valid |target_thread_type| for
67 // ScopedBoostPriority.
68 if (to == ThreadType::kRealtimeAudio)
69 continue;
70 Thread thread("ScopedThreadPriorityTest");
71 thread.StartWithOptions(Thread::Options(from));
72 thread.WaitUntilThreadStarted();
73 thread.task_runner()->PostTask(
74 FROM_HERE,
75 BindOnce(
76 [](ThreadType from, ThreadType to) {
77 EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
78 {
79 ScopedBoostPriority scoped_boost_priority(to);
80 bool will_boost_priority =
81 from < to &&
82 PlatformThread::CanChangeThreadType(from, to) &&
83 PlatformThread::CanChangeThreadType(to, from);
84 EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
85 will_boost_priority ? to : from);
86 }
87 EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
88 },
89 from, to));
90 }
91 }
92 }
93
TEST_F(ScopedThreadPriorityTest,WithoutPriorityBoost)94 TEST_F(ScopedThreadPriorityTest, WithoutPriorityBoost) {
95 ASSERT_RUNS_ONCE();
96
97 // Validates that a thread at normal priority keep the same priority.
98 {
99 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
100 EXPECT_EQ(ThreadPriorityForTest::kNormal,
101 PlatformThread::GetCurrentThreadPriorityForTest());
102 }
103 EXPECT_EQ(ThreadPriorityForTest::kNormal,
104 PlatformThread::GetCurrentThreadPriorityForTest());
105 }
106
107 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,WithPriorityBoost)108 TEST_F(ScopedThreadPriorityTest, WithPriorityBoost) {
109 ASSERT_RUNS_ONCE();
110
111 // Validates that a thread at background priority is boosted to normal
112 // priority.
113 PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
114 {
115 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
116 EXPECT_EQ(ThreadPriorityForTest::kNormal,
117 PlatformThread::GetCurrentThreadPriorityForTest());
118 }
119 EXPECT_EQ(ThreadPriorityForTest::kBackground,
120 PlatformThread::GetCurrentThreadPriorityForTest());
121
122 // Put back the default thread priority.
123 PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
124 }
125 #endif // BUILDFLAG(IS_WIN)
126
127 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,NestedScope)128 TEST_F(ScopedThreadPriorityTest, NestedScope) {
129 ASSERT_RUNS_ONCE();
130
131 PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
132
133 {
134 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
135 EXPECT_EQ(ThreadPriorityForTest::kNormal,
136 PlatformThread::GetCurrentThreadPriorityForTest());
137 {
138 SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
139 EXPECT_EQ(ThreadPriorityForTest::kNormal,
140 PlatformThread::GetCurrentThreadPriorityForTest());
141 }
142 EXPECT_EQ(ThreadPriorityForTest::kNormal,
143 PlatformThread::GetCurrentThreadPriorityForTest());
144 }
145
146 EXPECT_EQ(ThreadPriorityForTest::kBackground,
147 PlatformThread::GetCurrentThreadPriorityForTest());
148
149 // Put back the default thread priority.
150 PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
151 }
152 #endif // BUILDFLAG(IS_WIN)
153
154 #if BUILDFLAG(IS_WIN)
TEST_F(ScopedThreadPriorityTest,FunctionThatBoostsPriorityOnFirstInvoke)155 TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnFirstInvoke) {
156 ASSERT_RUNS_ONCE();
157
158 PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
159
160 FunctionThatBoostsPriorityOnFirstInvoke(base::ThreadPriorityForTest::kNormal);
161 FunctionThatBoostsPriorityOnFirstInvoke(
162 base::ThreadPriorityForTest::kBackground);
163
164 // Put back the default thread priority.
165 PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
166 }
167
TEST_F(ScopedThreadPriorityTest,FunctionThatBoostsPriorityOnEveryInvoke)168 TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnEveryInvoke) {
169 PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
170
171 FunctionThatBoostsPriorityOnEveryInvoke();
172 FunctionThatBoostsPriorityOnEveryInvoke();
173
174 // Put back the default thread priority.
175 PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
176 }
177
178 #endif // BUILDFLAG(IS_WIN)
179
180 } // namespace base
181