181 lines
6.1 KiB
C++
181 lines
6.1 KiB
C++
// Copyright 2019 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/threading/scoped_thread_priority.h"
|
|
|
|
#include "base/threading/platform_thread.h"
|
|
#include "base/threading/thread.h"
|
|
#include "build/build_config.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace base {
|
|
|
|
namespace {
|
|
|
|
// Tests in this file invoke an API that tracks state in static variable. They
|
|
// can therefore only be invoked once per process.
|
|
#define ASSERT_RUNS_ONCE() \
|
|
static int num_times_run = 0; \
|
|
++num_times_run; \
|
|
if (num_times_run > 1) \
|
|
ADD_FAILURE() << "This test cannot run multiple times in the same " \
|
|
"process.";
|
|
|
|
static ThreadType kAllThreadTypes[] = {
|
|
ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
|
|
ThreadType::kCompositing, ThreadType::kDefault, ThreadType::kBackground};
|
|
|
|
static_assert(static_cast<int>(ThreadType::kBackground) == 0,
|
|
"kBackground isn't lowest");
|
|
static_assert(ThreadType::kRealtimeAudio == ThreadType::kMaxValue,
|
|
"kRealtimeAudio isn't highest");
|
|
|
|
class ScopedThreadPriorityTest : public testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
// Ensures the default thread priority is set.
|
|
ASSERT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
};
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
void FunctionThatBoostsPriorityOnFirstInvoke(
|
|
ThreadPriorityForTest expected_priority) {
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
|
|
EXPECT_EQ(expected_priority,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
|
|
void FunctionThatBoostsPriorityOnEveryInvoke() {
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY_REPEATEDLY();
|
|
EXPECT_EQ(base::ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
} // namespace
|
|
|
|
TEST_F(ScopedThreadPriorityTest, BasicTest) {
|
|
for (auto from : kAllThreadTypes) {
|
|
if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from))
|
|
continue;
|
|
for (auto to : kAllThreadTypes) {
|
|
// ThreadType::kRealtimeAudio is not a valid |target_thread_type| for
|
|
// ScopedBoostPriority.
|
|
if (to == ThreadType::kRealtimeAudio)
|
|
continue;
|
|
Thread thread("ScopedThreadPriorityTest");
|
|
thread.StartWithOptions(Thread::Options(from));
|
|
thread.WaitUntilThreadStarted();
|
|
thread.task_runner()->PostTask(
|
|
FROM_HERE,
|
|
BindOnce(
|
|
[](ThreadType from, ThreadType to) {
|
|
EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
|
|
{
|
|
ScopedBoostPriority scoped_boost_priority(to);
|
|
bool will_boost_priority =
|
|
from < to &&
|
|
PlatformThread::CanChangeThreadType(from, to) &&
|
|
PlatformThread::CanChangeThreadType(to, from);
|
|
EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
|
|
will_boost_priority ? to : from);
|
|
}
|
|
EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from);
|
|
},
|
|
from, to));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(ScopedThreadPriorityTest, WithoutPriorityBoost) {
|
|
ASSERT_RUNS_ONCE();
|
|
|
|
// Validates that a thread at normal priority keep the same priority.
|
|
{
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
TEST_F(ScopedThreadPriorityTest, WithPriorityBoost) {
|
|
ASSERT_RUNS_ONCE();
|
|
|
|
// Validates that a thread at background priority is boosted to normal
|
|
// priority.
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
|
|
{
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
EXPECT_EQ(ThreadPriorityForTest::kBackground,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
|
|
// Put back the default thread priority.
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
|
|
}
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
TEST_F(ScopedThreadPriorityTest, NestedScope) {
|
|
ASSERT_RUNS_ONCE();
|
|
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
|
|
|
|
{
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
{
|
|
SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
EXPECT_EQ(ThreadPriorityForTest::kNormal,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
}
|
|
|
|
EXPECT_EQ(ThreadPriorityForTest::kBackground,
|
|
PlatformThread::GetCurrentThreadPriorityForTest());
|
|
|
|
// Put back the default thread priority.
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
|
|
}
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnFirstInvoke) {
|
|
ASSERT_RUNS_ONCE();
|
|
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
|
|
|
|
FunctionThatBoostsPriorityOnFirstInvoke(base::ThreadPriorityForTest::kNormal);
|
|
FunctionThatBoostsPriorityOnFirstInvoke(
|
|
base::ThreadPriorityForTest::kBackground);
|
|
|
|
// Put back the default thread priority.
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
|
|
}
|
|
|
|
TEST_F(ScopedThreadPriorityTest, FunctionThatBoostsPriorityOnEveryInvoke) {
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kBackground);
|
|
|
|
FunctionThatBoostsPriorityOnEveryInvoke();
|
|
FunctionThatBoostsPriorityOnEveryInvoke();
|
|
|
|
// Put back the default thread priority.
|
|
PlatformThread::SetCurrentThreadType(ThreadType::kDefault);
|
|
}
|
|
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
} // namespace base
|