xref: /aosp_15_r20/external/cronet/base/threading/scoped_thread_priority_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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