123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/threading/platform_thread.h"
- #include <stddef.h>
- #include "base/compiler_specific.h"
- #include "base/process/process.h"
- #include "base/synchronization/waitable_event.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/threading/thread.h"
- #include "base/threading/threading_features.h"
- #include "build/build_config.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #if BUILDFLAG(IS_POSIX)
- #include "base/threading/platform_thread_internal_posix.h"
- #elif BUILDFLAG(IS_WIN)
- #include <windows.h>
- #include "base/threading/platform_thread_win.h"
- #endif
- #if BUILDFLAG(IS_APPLE)
- #include <mach/mach.h>
- #include <mach/mach_time.h>
- #include <mach/thread_policy.h>
- #include "base/mac/mac_util.h"
- #include "base/metrics/field_trial_params.h"
- #include "base/time/time.h"
- #endif
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- #include <pthread.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #endif
- namespace base {
- // Trivial tests that thread runs and doesn't crash on create, join, or detach -
- namespace {
- class TrivialThread : public PlatformThread::Delegate {
- public:
- TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED) {}
- TrivialThread(const TrivialThread&) = delete;
- TrivialThread& operator=(const TrivialThread&) = delete;
- void ThreadMain() override { run_event_.Signal(); }
- WaitableEvent& run_event() { return run_event_; }
- private:
- WaitableEvent run_event_;
- };
- } // namespace
- TEST(PlatformThreadTest, TrivialJoin) {
- TrivialThread thread;
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.run_event().IsSignaled());
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_TRUE(thread.run_event().IsSignaled());
- }
- TEST(PlatformThreadTest, TrivialJoinTimesTen) {
- TrivialThread thread[10];
- PlatformThreadHandle handle[std::size(thread)];
- for (auto& n : thread)
- ASSERT_FALSE(n.run_event().IsSignaled());
- for (size_t n = 0; n < std::size(thread); n++)
- ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
- for (auto n : handle)
- PlatformThread::Join(n);
- for (auto& n : thread)
- ASSERT_TRUE(n.run_event().IsSignaled());
- }
- // The following detach tests are by nature racy. The run_event approximates the
- // end and termination of the thread, but threads could persist shortly after
- // the test completes.
- TEST(PlatformThreadTest, TrivialDetach) {
- TrivialThread thread;
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.run_event().IsSignaled());
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Detach(handle);
- thread.run_event().Wait();
- }
- TEST(PlatformThreadTest, TrivialDetachTimesTen) {
- TrivialThread thread[10];
- PlatformThreadHandle handle[std::size(thread)];
- for (auto& n : thread)
- ASSERT_FALSE(n.run_event().IsSignaled());
- for (size_t n = 0; n < std::size(thread); n++) {
- ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
- PlatformThread::Detach(handle[n]);
- }
- for (auto& n : thread)
- n.run_event().Wait();
- }
- // Tests of basic thread functions ---------------------------------------------
- namespace {
- class FunctionTestThread : public PlatformThread::Delegate {
- public:
- FunctionTestThread()
- : thread_id_(kInvalidThreadId),
- termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED),
- terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
- WaitableEvent::InitialState::NOT_SIGNALED),
- done_(false) {}
- FunctionTestThread(const FunctionTestThread&) = delete;
- FunctionTestThread& operator=(const FunctionTestThread&) = delete;
- ~FunctionTestThread() override {
- EXPECT_TRUE(terminate_thread_.IsSignaled())
- << "Need to mark thread for termination and join the underlying thread "
- << "before destroying a FunctionTestThread as it owns the "
- << "WaitableEvent blocking the underlying thread's main.";
- }
- // Grabs |thread_id_|, runs an optional test on that thread, signals
- // |termination_ready_|, and then waits for |terminate_thread_| to be
- // signaled before exiting.
- void ThreadMain() override {
- thread_id_ = PlatformThread::CurrentId();
- EXPECT_NE(thread_id_, kInvalidThreadId);
- // Make sure that the thread ID is the same across calls.
- EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
- // Run extra tests.
- RunTest();
- termination_ready_.Signal();
- terminate_thread_.Wait();
- done_ = true;
- }
- PlatformThreadId thread_id() const {
- EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
- return thread_id_;
- }
- bool IsRunning() const {
- return termination_ready_.IsSignaled() && !done_;
- }
- // Blocks until this thread is started and ready to be terminated.
- void WaitForTerminationReady() { termination_ready_.Wait(); }
- // Marks this thread for termination (callers must then join this thread to be
- // guaranteed of termination).
- void MarkForTermination() { terminate_thread_.Signal(); }
- private:
- // Runs an optional test on the newly created thread.
- virtual void RunTest() {}
- PlatformThreadId thread_id_;
- mutable WaitableEvent termination_ready_;
- WaitableEvent terminate_thread_;
- bool done_;
- };
- } // namespace
- TEST(PlatformThreadTest, Function) {
- PlatformThreadId main_thread_id = PlatformThread::CurrentId();
- FunctionTestThread thread;
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.IsRunning());
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForTerminationReady();
- ASSERT_TRUE(thread.IsRunning());
- EXPECT_NE(thread.thread_id(), main_thread_id);
- thread.MarkForTermination();
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.IsRunning());
- // Make sure that the thread ID is the same across calls.
- EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
- }
- TEST(PlatformThreadTest, FunctionTimesTen) {
- PlatformThreadId main_thread_id = PlatformThread::CurrentId();
- FunctionTestThread thread[10];
- PlatformThreadHandle handle[std::size(thread)];
- for (const auto& n : thread)
- ASSERT_FALSE(n.IsRunning());
- for (size_t n = 0; n < std::size(thread); n++)
- ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
- for (auto& n : thread)
- n.WaitForTerminationReady();
- for (size_t n = 0; n < std::size(thread); n++) {
- ASSERT_TRUE(thread[n].IsRunning());
- EXPECT_NE(thread[n].thread_id(), main_thread_id);
- // Make sure no two threads get the same ID.
- for (size_t i = 0; i < n; ++i) {
- EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
- }
- }
- for (auto& n : thread)
- n.MarkForTermination();
- for (auto n : handle)
- PlatformThread::Join(n);
- for (const auto& n : thread)
- ASSERT_FALSE(n.IsRunning());
- // Make sure that the thread ID is the same across calls.
- EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
- }
- namespace {
- constexpr ThreadType kAllThreadTypes[] = {
- ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
- ThreadType::kCompositing, ThreadType::kDefault,
- ThreadType::kResourceEfficient, ThreadType::kBackground};
- class ThreadTypeTestThread : public FunctionTestThread {
- public:
- explicit ThreadTypeTestThread(ThreadType from, ThreadType to)
- : from_(from), to_(to) {}
- ThreadTypeTestThread(const ThreadTypeTestThread&) = delete;
- ThreadTypeTestThread& operator=(const ThreadTypeTestThread&) = delete;
- ~ThreadTypeTestThread() override = default;
- private:
- void RunTest() override {
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
- PlatformThread::SetCurrentThreadType(from_);
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from_);
- PlatformThread::SetCurrentThreadType(to_);
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(), to_);
- }
- const ThreadType from_;
- const ThreadType to_;
- };
- class ThreadPriorityTestThread : public FunctionTestThread {
- public:
- ThreadPriorityTestThread(ThreadType thread_type,
- ThreadPriorityForTest priority)
- : thread_type_(thread_type), priority(priority) {}
- private:
- void RunTest() override {
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
- PlatformThread::SetCurrentThreadType(thread_type_);
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(), thread_type_);
- if (PlatformThread::CanChangeThreadType(ThreadType::kDefault,
- thread_type_)) {
- EXPECT_EQ(PlatformThread::GetCurrentThreadPriorityForTest(), priority);
- }
- }
- const ThreadType thread_type_;
- const ThreadPriorityForTest priority;
- };
- void TestSetCurrentThreadType() {
- for (auto from : kAllThreadTypes) {
- if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from)) {
- continue;
- }
- for (auto to : kAllThreadTypes) {
- ThreadTypeTestThread thread(from, to);
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.IsRunning());
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForTerminationReady();
- ASSERT_TRUE(thread.IsRunning());
- thread.MarkForTermination();
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.IsRunning());
- }
- }
- }
- void TestPriorityResultingFromThreadType(ThreadType thread_type,
- ThreadPriorityForTest priority) {
- ThreadPriorityTestThread thread(thread_type, priority);
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.IsRunning());
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- thread.WaitForTerminationReady();
- ASSERT_TRUE(thread.IsRunning());
- thread.MarkForTermination();
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.IsRunning());
- }
- ThreadPriorityForTest GetCurrentThreadPriorityIfStartWithThreadType(
- ThreadType thread_type,
- MessagePumpType message_pump_type) {
- Thread::Options options;
- options.thread_type = thread_type;
- options.message_pump_type = message_pump_type;
- Thread thread("GetCurrentThreadPriorityIfStartWithThreadType");
- thread.StartWithOptions(std::move(options));
- thread.WaitUntilThreadStarted();
- ThreadPriorityForTest priority;
- thread.task_runner()->PostTask(
- FROM_HERE, BindOnce(
- [](ThreadPriorityForTest* priority) {
- *priority =
- PlatformThread::GetCurrentThreadPriorityForTest();
- },
- &priority));
- thread.Stop();
- return priority;
- }
- ThreadPriorityForTest GetCurrentThreadPriorityIfSetThreadTypeLater(
- ThreadType thread_type,
- MessagePumpType message_pump_type) {
- Thread::Options options;
- options.message_pump_type = message_pump_type;
- Thread thread("GetCurrentThreadPriorityIfSetThreadTypeLater");
- thread.StartWithOptions(std::move(options));
- thread.WaitUntilThreadStarted();
- ThreadPriorityForTest priority;
- thread.task_runner()->PostTask(
- FROM_HERE,
- BindOnce(
- [](ThreadType thread_type, ThreadPriorityForTest* priority) {
- PlatformThread::SetCurrentThreadType(thread_type);
- *priority = PlatformThread::GetCurrentThreadPriorityForTest();
- },
- thread_type, &priority));
- thread.Stop();
- return priority;
- }
- void TestPriorityResultingFromThreadType(ThreadType thread_type,
- MessagePumpType message_pump_type,
- ThreadPriorityForTest priority) {
- testing::Message message;
- message << "thread_type: " << static_cast<int>(thread_type)
- << ", message_pump_type: " << static_cast<int>(message_pump_type);
- SCOPED_TRACE(message);
- if (PlatformThread::CanChangeThreadType(ThreadType::kDefault, thread_type)) {
- EXPECT_EQ(GetCurrentThreadPriorityIfStartWithThreadType(thread_type,
- message_pump_type),
- priority);
- EXPECT_EQ(GetCurrentThreadPriorityIfSetThreadTypeLater(thread_type,
- message_pump_type),
- priority);
- }
- }
- } // namespace
- // Test changing a created thread's type.
- TEST(PlatformThreadTest, SetCurrentThreadType) {
- TestSetCurrentThreadType();
- }
- #if BUILDFLAG(IS_WIN)
- // Test changing a created thread's priority in an IDLE_PRIORITY_CLASS process
- // (regression test for https://crbug.com/901483).
- TEST(PlatformThreadTest,
- SetCurrentThreadTypeWithThreadModeBackgroundIdleProcess) {
- ::SetPriorityClass(Process::Current().Handle(), IDLE_PRIORITY_CLASS);
- TestSetCurrentThreadType();
- ::SetPriorityClass(Process::Current().Handle(), NORMAL_PRIORITY_CLASS);
- }
- #endif // BUILDFLAG(IS_WIN)
- // Ideally PlatformThread::CanChangeThreadType() would be true on all
- // platforms for all priorities. This not being the case. This test documents
- // and hardcodes what we know. Please inform scheduler-dev@chromium.org if this
- // proprerty changes for a given platform.
- TEST(PlatformThreadTest, CanChangeThreadType) {
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // On Ubuntu, RLIMIT_NICE and RLIMIT_RTPRIO are 0 by default, so we won't be
- // able to increase priority to any level.
- constexpr bool kCanIncreasePriority = false;
- #else
- constexpr bool kCanIncreasePriority = true;
- #endif
- for (auto type : kAllThreadTypes) {
- EXPECT_TRUE(PlatformThread::CanChangeThreadType(type, type));
- }
- #if BUILDFLAG(IS_FUCHSIA)
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(
- ThreadType::kBackground, ThreadType::kResourceEfficient));
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kDefault));
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kCompositing));
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
- ThreadType::kBackground));
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
- ThreadType::kBackground));
- #else
- EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kResourceEfficient),
- kCanIncreasePriority);
- EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kDefault),
- kCanIncreasePriority);
- EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kCompositing),
- kCanIncreasePriority);
- EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
- ThreadType::kBackground));
- EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
- ThreadType::kBackground));
- #endif
- EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kDisplayCritical),
- kCanIncreasePriority);
- EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
- ThreadType::kRealtimeAudio),
- kCanIncreasePriority);
- #if BUILDFLAG(IS_FUCHSIA)
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
- ThreadType::kBackground));
- EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
- ThreadType::kBackground));
- #else
- EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
- ThreadType::kBackground));
- EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
- ThreadType::kBackground));
- #endif
- }
- TEST(PlatformThreadTest, SetCurrentThreadTypeTest) {
- TestPriorityResultingFromThreadType(ThreadType::kBackground,
- ThreadPriorityForTest::kBackground);
- TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
- ThreadPriorityForTest::kNormal);
- TestPriorityResultingFromThreadType(ThreadType::kDefault,
- ThreadPriorityForTest::kNormal);
- #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- ThreadPriorityForTest::kDisplay);
- #if BUILDFLAG(IS_WIN)
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- MessagePumpType::UI,
- ThreadPriorityForTest::kNormal);
- #else
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- MessagePumpType::UI,
- ThreadPriorityForTest::kDisplay);
- #endif // BUILDFLAG(IS_WIN)
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- MessagePumpType::IO,
- ThreadPriorityForTest::kDisplay);
- #else // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- ThreadPriorityForTest::kNormal);
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- MessagePumpType::UI,
- ThreadPriorityForTest::kNormal);
- TestPriorityResultingFromThreadType(ThreadType::kCompositing,
- MessagePumpType::IO,
- ThreadPriorityForTest::kNormal);
- #endif
- TestPriorityResultingFromThreadType(ThreadType::kDisplayCritical,
- ThreadPriorityForTest::kDisplay);
- TestPriorityResultingFromThreadType(ThreadType::kRealtimeAudio,
- ThreadPriorityForTest::kRealtimeAudio);
- }
- TEST(PlatformThreadTest, SetHugeThreadName) {
- // Construct an excessively long thread name.
- std::string long_name(1024, 'a');
- // SetName has no return code, so just verify that implementations
- // don't [D]CHECK().
- PlatformThread::SetName(long_name);
- }
- TEST(PlatformThreadTest, GetDefaultThreadStackSize) {
- size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
- #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) || \
- ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
- !defined(THREAD_SANITIZER)) || \
- (BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER))
- EXPECT_EQ(0u, stack_size);
- #else
- EXPECT_GT(stack_size, 0u);
- EXPECT_LT(stack_size, 20u * (1 << 20));
- #endif
- }
- #if BUILDFLAG(IS_APPLE)
- namespace {
- class RealtimeTestThread : public FunctionTestThread {
- public:
- explicit RealtimeTestThread(TimeDelta realtime_period)
- : realtime_period_(realtime_period) {}
- ~RealtimeTestThread() override = default;
- private:
- RealtimeTestThread(const RealtimeTestThread&) = delete;
- RealtimeTestThread& operator=(const RealtimeTestThread&) = delete;
- TimeDelta GetRealtimePeriod() final { return realtime_period_; }
- // Verifies the realtime thead configuration.
- void RunTest() override {
- EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
- ThreadType::kRealtimeAudio);
- mach_port_t mach_thread_id = pthread_mach_thread_np(
- PlatformThread::CurrentHandle().platform_handle());
- // |count| and |get_default| chosen impirically so that
- // time_constraints_buffer[0] would store the last constraints that were
- // applied.
- const int kPolicyCount = 32;
- thread_time_constraint_policy_data_t time_constraints_buffer[kPolicyCount];
- mach_msg_type_number_t count = kPolicyCount;
- boolean_t get_default = 0;
- kern_return_t result = thread_policy_get(
- mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
- reinterpret_cast<thread_policy_t>(time_constraints_buffer), &count,
- &get_default);
- EXPECT_EQ(result, KERN_SUCCESS);
- const thread_time_constraint_policy_data_t& time_constraints =
- time_constraints_buffer[0];
- mach_timebase_info_data_t tb_info;
- mach_timebase_info(&tb_info);
- if (FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac) &&
- #if BUILDFLAG(IS_MAC)
- !mac::IsOS10_14() && // Should not be applied on 10.14.
- #endif
- !realtime_period_.is_zero()) {
- uint32_t abs_realtime_period = saturated_cast<uint32_t>(
- realtime_period_.InNanoseconds() *
- (static_cast<double>(tb_info.denom) / tb_info.numer));
- EXPECT_EQ(time_constraints.period, abs_realtime_period);
- EXPECT_EQ(
- time_constraints.computation,
- static_cast<uint32_t>(abs_realtime_period *
- kOptimizedRealtimeThreadingMacBusy.Get()));
- EXPECT_EQ(
- time_constraints.constraint,
- static_cast<uint32_t>(abs_realtime_period *
- kOptimizedRealtimeThreadingMacBusyLimit.Get()));
- EXPECT_EQ(time_constraints.preemptible,
- kOptimizedRealtimeThreadingMacPreemptible.Get());
- } else {
- // Old-style empirical values.
- const double kTimeQuantum = 2.9;
- const double kAudioTimeNeeded = 0.75 * kTimeQuantum;
- const double kMaxTimeAllowed = 0.85 * kTimeQuantum;
- // Get the conversion factor from milliseconds to absolute time
- // which is what the time-constraints returns.
- double ms_to_abs_time = double(tb_info.denom) / tb_info.numer * 1000000;
- EXPECT_EQ(time_constraints.period,
- saturated_cast<uint32_t>(kTimeQuantum * ms_to_abs_time));
- EXPECT_EQ(time_constraints.computation,
- saturated_cast<uint32_t>(kAudioTimeNeeded * ms_to_abs_time));
- EXPECT_EQ(time_constraints.constraint,
- saturated_cast<uint32_t>(kMaxTimeAllowed * ms_to_abs_time));
- EXPECT_FALSE(time_constraints.preemptible);
- }
- }
- const TimeDelta realtime_period_;
- };
- class RealtimePlatformThreadTest
- : public testing::TestWithParam<
- std::tuple<bool, FieldTrialParams, TimeDelta>> {
- protected:
- void VerifyRealtimeConfig(TimeDelta period) {
- RealtimeTestThread thread(period);
- PlatformThreadHandle handle;
- ASSERT_FALSE(thread.IsRunning());
- ASSERT_TRUE(PlatformThread::CreateWithType(0, &thread, &handle,
- ThreadType::kRealtimeAudio));
- thread.WaitForTerminationReady();
- ASSERT_TRUE(thread.IsRunning());
- thread.MarkForTermination();
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.IsRunning());
- }
- };
- TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMac) {
- test::ScopedFeatureList feature_list;
- if (std::get<0>(GetParam())) {
- feature_list.InitAndEnableFeatureWithParameters(
- kOptimizedRealtimeThreadingMac, std::get<1>(GetParam()));
- } else {
- feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac);
- }
- PlatformThread::InitializeOptimizedRealtimeThreadingFeature();
- VerifyRealtimeConfig(std::get<2>(GetParam()));
- }
- INSTANTIATE_TEST_SUITE_P(
- RealtimePlatformThreadTest,
- RealtimePlatformThreadTest,
- testing::Combine(
- testing::Bool(),
- testing::Values(
- FieldTrialParams{
- {kOptimizedRealtimeThreadingMacPreemptible.name, "true"}},
- FieldTrialParams{
- {kOptimizedRealtimeThreadingMacPreemptible.name, "false"}},
- FieldTrialParams{
- {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
- {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.75"}},
- FieldTrialParams{
- {kOptimizedRealtimeThreadingMacBusy.name, "0.7"},
- {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.7"}},
- FieldTrialParams{
- {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
- {kOptimizedRealtimeThreadingMacBusyLimit.name, "1.0"}}),
- testing::Values(TimeDelta(),
- Seconds(256.0 / 48000),
- Milliseconds(5),
- Milliseconds(10),
- Seconds(1024.0 / 44100),
- Seconds(1024.0 / 16000))));
- } // namespace
- #endif // BUILDFLAG(IS_APPLE)
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- namespace {
- bool IsTidCacheCorrect() {
- return PlatformThread::CurrentId() == syscall(__NR_gettid);
- }
- void* CheckTidCacheCorrectWrapper(void*) {
- CHECK(IsTidCacheCorrect());
- return nullptr;
- }
- void CreatePthreadToCheckCache() {
- pthread_t thread_id;
- pthread_create(&thread_id, nullptr, CheckTidCacheCorrectWrapper, nullptr);
- pthread_join(thread_id, nullptr);
- }
- // This test must use raw pthreads and fork() to avoid calls from //base to
- // PlatformThread::CurrentId(), as the ordering of calls is important to the
- // test.
- void TestTidCacheCorrect(bool main_thread_accesses_cache_first) {
- EXPECT_TRUE(IsTidCacheCorrect());
- CreatePthreadToCheckCache();
- // Now fork a process and make sure the TID cache gets correctly updated on
- // both its main thread and a child thread.
- pid_t child_pid = fork();
- ASSERT_GE(child_pid, 0);
- if (child_pid == 0) {
- // In the child.
- if (main_thread_accesses_cache_first) {
- if (!IsTidCacheCorrect())
- _exit(1);
- }
- // Access the TID cache on another thread and make sure the cached value is
- // correct.
- CreatePthreadToCheckCache();
- if (!main_thread_accesses_cache_first) {
- // Make sure the main thread's cache is correct even though another thread
- // accessed the cache first.
- if (!IsTidCacheCorrect())
- _exit(1);
- }
- _exit(0);
- }
- int status;
- ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid);
- ASSERT_TRUE(WIFEXITED(status));
- ASSERT_EQ(WEXITSTATUS(status), 0);
- }
- TEST(PlatformThreadTidCacheTest, MainThreadFirst) {
- TestTidCacheCorrect(true);
- }
- TEST(PlatformThreadTidCacheTest, MainThreadSecond) {
- TestTidCacheCorrect(false);
- }
- } // namespace
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- } // namespace base
|