• 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/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