platform_thread_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/threading/platform_thread.h"
  5. #include <stddef.h>
  6. #include "base/compiler_specific.h"
  7. #include "base/process/process.h"
  8. #include "base/synchronization/waitable_event.h"
  9. #include "base/test/scoped_feature_list.h"
  10. #include "base/threading/thread.h"
  11. #include "base/threading/threading_features.h"
  12. #include "build/build_config.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. #if BUILDFLAG(IS_POSIX)
  15. #include "base/threading/platform_thread_internal_posix.h"
  16. #elif BUILDFLAG(IS_WIN)
  17. #include <windows.h>
  18. #include "base/threading/platform_thread_win.h"
  19. #endif
  20. #if BUILDFLAG(IS_APPLE)
  21. #include <mach/mach.h>
  22. #include <mach/mach_time.h>
  23. #include <mach/thread_policy.h>
  24. #include "base/mac/mac_util.h"
  25. #include "base/metrics/field_trial_params.h"
  26. #include "base/time/time.h"
  27. #endif
  28. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  29. #include <pthread.h>
  30. #include <sys/syscall.h>
  31. #include <sys/types.h>
  32. #include <sys/wait.h>
  33. #include <unistd.h>
  34. #endif
  35. namespace base {
  36. // Trivial tests that thread runs and doesn't crash on create, join, or detach -
  37. namespace {
  38. class TrivialThread : public PlatformThread::Delegate {
  39. public:
  40. TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL,
  41. WaitableEvent::InitialState::NOT_SIGNALED) {}
  42. TrivialThread(const TrivialThread&) = delete;
  43. TrivialThread& operator=(const TrivialThread&) = delete;
  44. void ThreadMain() override { run_event_.Signal(); }
  45. WaitableEvent& run_event() { return run_event_; }
  46. private:
  47. WaitableEvent run_event_;
  48. };
  49. } // namespace
  50. TEST(PlatformThreadTest, TrivialJoin) {
  51. TrivialThread thread;
  52. PlatformThreadHandle handle;
  53. ASSERT_FALSE(thread.run_event().IsSignaled());
  54. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  55. PlatformThread::Join(handle);
  56. ASSERT_TRUE(thread.run_event().IsSignaled());
  57. }
  58. TEST(PlatformThreadTest, TrivialJoinTimesTen) {
  59. TrivialThread thread[10];
  60. PlatformThreadHandle handle[std::size(thread)];
  61. for (auto& n : thread)
  62. ASSERT_FALSE(n.run_event().IsSignaled());
  63. for (size_t n = 0; n < std::size(thread); n++)
  64. ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
  65. for (auto n : handle)
  66. PlatformThread::Join(n);
  67. for (auto& n : thread)
  68. ASSERT_TRUE(n.run_event().IsSignaled());
  69. }
  70. // The following detach tests are by nature racy. The run_event approximates the
  71. // end and termination of the thread, but threads could persist shortly after
  72. // the test completes.
  73. TEST(PlatformThreadTest, TrivialDetach) {
  74. TrivialThread thread;
  75. PlatformThreadHandle handle;
  76. ASSERT_FALSE(thread.run_event().IsSignaled());
  77. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  78. PlatformThread::Detach(handle);
  79. thread.run_event().Wait();
  80. }
  81. TEST(PlatformThreadTest, TrivialDetachTimesTen) {
  82. TrivialThread thread[10];
  83. PlatformThreadHandle handle[std::size(thread)];
  84. for (auto& n : thread)
  85. ASSERT_FALSE(n.run_event().IsSignaled());
  86. for (size_t n = 0; n < std::size(thread); n++) {
  87. ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
  88. PlatformThread::Detach(handle[n]);
  89. }
  90. for (auto& n : thread)
  91. n.run_event().Wait();
  92. }
  93. // Tests of basic thread functions ---------------------------------------------
  94. namespace {
  95. class FunctionTestThread : public PlatformThread::Delegate {
  96. public:
  97. FunctionTestThread()
  98. : thread_id_(kInvalidThreadId),
  99. termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
  100. WaitableEvent::InitialState::NOT_SIGNALED),
  101. terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
  102. WaitableEvent::InitialState::NOT_SIGNALED),
  103. done_(false) {}
  104. FunctionTestThread(const FunctionTestThread&) = delete;
  105. FunctionTestThread& operator=(const FunctionTestThread&) = delete;
  106. ~FunctionTestThread() override {
  107. EXPECT_TRUE(terminate_thread_.IsSignaled())
  108. << "Need to mark thread for termination and join the underlying thread "
  109. << "before destroying a FunctionTestThread as it owns the "
  110. << "WaitableEvent blocking the underlying thread's main.";
  111. }
  112. // Grabs |thread_id_|, runs an optional test on that thread, signals
  113. // |termination_ready_|, and then waits for |terminate_thread_| to be
  114. // signaled before exiting.
  115. void ThreadMain() override {
  116. thread_id_ = PlatformThread::CurrentId();
  117. EXPECT_NE(thread_id_, kInvalidThreadId);
  118. // Make sure that the thread ID is the same across calls.
  119. EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
  120. // Run extra tests.
  121. RunTest();
  122. termination_ready_.Signal();
  123. terminate_thread_.Wait();
  124. done_ = true;
  125. }
  126. PlatformThreadId thread_id() const {
  127. EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
  128. return thread_id_;
  129. }
  130. bool IsRunning() const {
  131. return termination_ready_.IsSignaled() && !done_;
  132. }
  133. // Blocks until this thread is started and ready to be terminated.
  134. void WaitForTerminationReady() { termination_ready_.Wait(); }
  135. // Marks this thread for termination (callers must then join this thread to be
  136. // guaranteed of termination).
  137. void MarkForTermination() { terminate_thread_.Signal(); }
  138. private:
  139. // Runs an optional test on the newly created thread.
  140. virtual void RunTest() {}
  141. PlatformThreadId thread_id_;
  142. mutable WaitableEvent termination_ready_;
  143. WaitableEvent terminate_thread_;
  144. bool done_;
  145. };
  146. } // namespace
  147. TEST(PlatformThreadTest, Function) {
  148. PlatformThreadId main_thread_id = PlatformThread::CurrentId();
  149. FunctionTestThread thread;
  150. PlatformThreadHandle handle;
  151. ASSERT_FALSE(thread.IsRunning());
  152. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  153. thread.WaitForTerminationReady();
  154. ASSERT_TRUE(thread.IsRunning());
  155. EXPECT_NE(thread.thread_id(), main_thread_id);
  156. thread.MarkForTermination();
  157. PlatformThread::Join(handle);
  158. ASSERT_FALSE(thread.IsRunning());
  159. // Make sure that the thread ID is the same across calls.
  160. EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
  161. }
  162. TEST(PlatformThreadTest, FunctionTimesTen) {
  163. PlatformThreadId main_thread_id = PlatformThread::CurrentId();
  164. FunctionTestThread thread[10];
  165. PlatformThreadHandle handle[std::size(thread)];
  166. for (const auto& n : thread)
  167. ASSERT_FALSE(n.IsRunning());
  168. for (size_t n = 0; n < std::size(thread); n++)
  169. ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
  170. for (auto& n : thread)
  171. n.WaitForTerminationReady();
  172. for (size_t n = 0; n < std::size(thread); n++) {
  173. ASSERT_TRUE(thread[n].IsRunning());
  174. EXPECT_NE(thread[n].thread_id(), main_thread_id);
  175. // Make sure no two threads get the same ID.
  176. for (size_t i = 0; i < n; ++i) {
  177. EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
  178. }
  179. }
  180. for (auto& n : thread)
  181. n.MarkForTermination();
  182. for (auto n : handle)
  183. PlatformThread::Join(n);
  184. for (const auto& n : thread)
  185. ASSERT_FALSE(n.IsRunning());
  186. // Make sure that the thread ID is the same across calls.
  187. EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
  188. }
  189. namespace {
  190. constexpr ThreadType kAllThreadTypes[] = {
  191. ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
  192. ThreadType::kCompositing, ThreadType::kDefault,
  193. ThreadType::kResourceEfficient, ThreadType::kBackground};
  194. class ThreadTypeTestThread : public FunctionTestThread {
  195. public:
  196. explicit ThreadTypeTestThread(ThreadType from, ThreadType to)
  197. : from_(from), to_(to) {}
  198. ThreadTypeTestThread(const ThreadTypeTestThread&) = delete;
  199. ThreadTypeTestThread& operator=(const ThreadTypeTestThread&) = delete;
  200. ~ThreadTypeTestThread() override = default;
  201. private:
  202. void RunTest() override {
  203. EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
  204. PlatformThread::SetCurrentThreadType(from_);
  205. EXPECT_EQ(PlatformThread::GetCurrentThreadType(), from_);
  206. PlatformThread::SetCurrentThreadType(to_);
  207. EXPECT_EQ(PlatformThread::GetCurrentThreadType(), to_);
  208. }
  209. const ThreadType from_;
  210. const ThreadType to_;
  211. };
  212. class ThreadPriorityTestThread : public FunctionTestThread {
  213. public:
  214. ThreadPriorityTestThread(ThreadType thread_type,
  215. ThreadPriorityForTest priority)
  216. : thread_type_(thread_type), priority(priority) {}
  217. private:
  218. void RunTest() override {
  219. EXPECT_EQ(PlatformThread::GetCurrentThreadType(), ThreadType::kDefault);
  220. PlatformThread::SetCurrentThreadType(thread_type_);
  221. EXPECT_EQ(PlatformThread::GetCurrentThreadType(), thread_type_);
  222. if (PlatformThread::CanChangeThreadType(ThreadType::kDefault,
  223. thread_type_)) {
  224. EXPECT_EQ(PlatformThread::GetCurrentThreadPriorityForTest(), priority);
  225. }
  226. }
  227. const ThreadType thread_type_;
  228. const ThreadPriorityForTest priority;
  229. };
  230. void TestSetCurrentThreadType() {
  231. for (auto from : kAllThreadTypes) {
  232. if (!PlatformThread::CanChangeThreadType(ThreadType::kDefault, from)) {
  233. continue;
  234. }
  235. for (auto to : kAllThreadTypes) {
  236. ThreadTypeTestThread thread(from, to);
  237. PlatformThreadHandle handle;
  238. ASSERT_FALSE(thread.IsRunning());
  239. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  240. thread.WaitForTerminationReady();
  241. ASSERT_TRUE(thread.IsRunning());
  242. thread.MarkForTermination();
  243. PlatformThread::Join(handle);
  244. ASSERT_FALSE(thread.IsRunning());
  245. }
  246. }
  247. }
  248. void TestPriorityResultingFromThreadType(ThreadType thread_type,
  249. ThreadPriorityForTest priority) {
  250. ThreadPriorityTestThread thread(thread_type, priority);
  251. PlatformThreadHandle handle;
  252. ASSERT_FALSE(thread.IsRunning());
  253. ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
  254. thread.WaitForTerminationReady();
  255. ASSERT_TRUE(thread.IsRunning());
  256. thread.MarkForTermination();
  257. PlatformThread::Join(handle);
  258. ASSERT_FALSE(thread.IsRunning());
  259. }
  260. ThreadPriorityForTest GetCurrentThreadPriorityIfStartWithThreadType(
  261. ThreadType thread_type,
  262. MessagePumpType message_pump_type) {
  263. Thread::Options options;
  264. options.thread_type = thread_type;
  265. options.message_pump_type = message_pump_type;
  266. Thread thread("GetCurrentThreadPriorityIfStartWithThreadType");
  267. thread.StartWithOptions(std::move(options));
  268. thread.WaitUntilThreadStarted();
  269. ThreadPriorityForTest priority;
  270. thread.task_runner()->PostTask(
  271. FROM_HERE, BindOnce(
  272. [](ThreadPriorityForTest* priority) {
  273. *priority =
  274. PlatformThread::GetCurrentThreadPriorityForTest();
  275. },
  276. &priority));
  277. thread.Stop();
  278. return priority;
  279. }
  280. ThreadPriorityForTest GetCurrentThreadPriorityIfSetThreadTypeLater(
  281. ThreadType thread_type,
  282. MessagePumpType message_pump_type) {
  283. Thread::Options options;
  284. options.message_pump_type = message_pump_type;
  285. Thread thread("GetCurrentThreadPriorityIfSetThreadTypeLater");
  286. thread.StartWithOptions(std::move(options));
  287. thread.WaitUntilThreadStarted();
  288. ThreadPriorityForTest priority;
  289. thread.task_runner()->PostTask(
  290. FROM_HERE,
  291. BindOnce(
  292. [](ThreadType thread_type, ThreadPriorityForTest* priority) {
  293. PlatformThread::SetCurrentThreadType(thread_type);
  294. *priority = PlatformThread::GetCurrentThreadPriorityForTest();
  295. },
  296. thread_type, &priority));
  297. thread.Stop();
  298. return priority;
  299. }
  300. void TestPriorityResultingFromThreadType(ThreadType thread_type,
  301. MessagePumpType message_pump_type,
  302. ThreadPriorityForTest priority) {
  303. testing::Message message;
  304. message << "thread_type: " << static_cast<int>(thread_type)
  305. << ", message_pump_type: " << static_cast<int>(message_pump_type);
  306. SCOPED_TRACE(message);
  307. if (PlatformThread::CanChangeThreadType(ThreadType::kDefault, thread_type)) {
  308. EXPECT_EQ(GetCurrentThreadPriorityIfStartWithThreadType(thread_type,
  309. message_pump_type),
  310. priority);
  311. EXPECT_EQ(GetCurrentThreadPriorityIfSetThreadTypeLater(thread_type,
  312. message_pump_type),
  313. priority);
  314. }
  315. }
  316. } // namespace
  317. // Test changing a created thread's type.
  318. TEST(PlatformThreadTest, SetCurrentThreadType) {
  319. TestSetCurrentThreadType();
  320. }
  321. #if BUILDFLAG(IS_WIN)
  322. // Test changing a created thread's priority in an IDLE_PRIORITY_CLASS process
  323. // (regression test for https://crbug.com/901483).
  324. TEST(PlatformThreadTest,
  325. SetCurrentThreadTypeWithThreadModeBackgroundIdleProcess) {
  326. ::SetPriorityClass(Process::Current().Handle(), IDLE_PRIORITY_CLASS);
  327. TestSetCurrentThreadType();
  328. ::SetPriorityClass(Process::Current().Handle(), NORMAL_PRIORITY_CLASS);
  329. }
  330. #endif // BUILDFLAG(IS_WIN)
  331. // Ideally PlatformThread::CanChangeThreadType() would be true on all
  332. // platforms for all priorities. This not being the case. This test documents
  333. // and hardcodes what we know. Please inform scheduler-dev@chromium.org if this
  334. // proprerty changes for a given platform.
  335. TEST(PlatformThreadTest, CanChangeThreadType) {
  336. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  337. // On Ubuntu, RLIMIT_NICE and RLIMIT_RTPRIO are 0 by default, so we won't be
  338. // able to increase priority to any level.
  339. constexpr bool kCanIncreasePriority = false;
  340. #else
  341. constexpr bool kCanIncreasePriority = true;
  342. #endif
  343. for (auto type : kAllThreadTypes) {
  344. EXPECT_TRUE(PlatformThread::CanChangeThreadType(type, type));
  345. }
  346. #if BUILDFLAG(IS_FUCHSIA)
  347. EXPECT_FALSE(PlatformThread::CanChangeThreadType(
  348. ThreadType::kBackground, ThreadType::kResourceEfficient));
  349. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  350. ThreadType::kDefault));
  351. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  352. ThreadType::kCompositing));
  353. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
  354. ThreadType::kBackground));
  355. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
  356. ThreadType::kBackground));
  357. #else
  358. EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  359. ThreadType::kResourceEfficient),
  360. kCanIncreasePriority);
  361. EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  362. ThreadType::kDefault),
  363. kCanIncreasePriority);
  364. EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  365. ThreadType::kCompositing),
  366. kCanIncreasePriority);
  367. EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
  368. ThreadType::kBackground));
  369. EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
  370. ThreadType::kBackground));
  371. #endif
  372. EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  373. ThreadType::kDisplayCritical),
  374. kCanIncreasePriority);
  375. EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
  376. ThreadType::kRealtimeAudio),
  377. kCanIncreasePriority);
  378. #if BUILDFLAG(IS_FUCHSIA)
  379. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
  380. ThreadType::kBackground));
  381. EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
  382. ThreadType::kBackground));
  383. #else
  384. EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
  385. ThreadType::kBackground));
  386. EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
  387. ThreadType::kBackground));
  388. #endif
  389. }
  390. TEST(PlatformThreadTest, SetCurrentThreadTypeTest) {
  391. TestPriorityResultingFromThreadType(ThreadType::kBackground,
  392. ThreadPriorityForTest::kBackground);
  393. TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
  394. ThreadPriorityForTest::kNormal);
  395. TestPriorityResultingFromThreadType(ThreadType::kDefault,
  396. ThreadPriorityForTest::kNormal);
  397. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
  398. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  399. ThreadPriorityForTest::kDisplay);
  400. #if BUILDFLAG(IS_WIN)
  401. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  402. MessagePumpType::UI,
  403. ThreadPriorityForTest::kNormal);
  404. #else
  405. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  406. MessagePumpType::UI,
  407. ThreadPriorityForTest::kDisplay);
  408. #endif // BUILDFLAG(IS_WIN)
  409. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  410. MessagePumpType::IO,
  411. ThreadPriorityForTest::kDisplay);
  412. #else // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
  413. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  414. ThreadPriorityForTest::kNormal);
  415. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  416. MessagePumpType::UI,
  417. ThreadPriorityForTest::kNormal);
  418. TestPriorityResultingFromThreadType(ThreadType::kCompositing,
  419. MessagePumpType::IO,
  420. ThreadPriorityForTest::kNormal);
  421. #endif
  422. TestPriorityResultingFromThreadType(ThreadType::kDisplayCritical,
  423. ThreadPriorityForTest::kDisplay);
  424. TestPriorityResultingFromThreadType(ThreadType::kRealtimeAudio,
  425. ThreadPriorityForTest::kRealtimeAudio);
  426. }
  427. TEST(PlatformThreadTest, SetHugeThreadName) {
  428. // Construct an excessively long thread name.
  429. std::string long_name(1024, 'a');
  430. // SetName has no return code, so just verify that implementations
  431. // don't [D]CHECK().
  432. PlatformThread::SetName(long_name);
  433. }
  434. TEST(PlatformThreadTest, GetDefaultThreadStackSize) {
  435. size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
  436. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) || \
  437. ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
  438. !defined(THREAD_SANITIZER)) || \
  439. (BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER))
  440. EXPECT_EQ(0u, stack_size);
  441. #else
  442. EXPECT_GT(stack_size, 0u);
  443. EXPECT_LT(stack_size, 20u * (1 << 20));
  444. #endif
  445. }
  446. #if BUILDFLAG(IS_APPLE)
  447. namespace {
  448. class RealtimeTestThread : public FunctionTestThread {
  449. public:
  450. explicit RealtimeTestThread(TimeDelta realtime_period)
  451. : realtime_period_(realtime_period) {}
  452. ~RealtimeTestThread() override = default;
  453. private:
  454. RealtimeTestThread(const RealtimeTestThread&) = delete;
  455. RealtimeTestThread& operator=(const RealtimeTestThread&) = delete;
  456. TimeDelta GetRealtimePeriod() final { return realtime_period_; }
  457. // Verifies the realtime thead configuration.
  458. void RunTest() override {
  459. EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
  460. ThreadType::kRealtimeAudio);
  461. mach_port_t mach_thread_id = pthread_mach_thread_np(
  462. PlatformThread::CurrentHandle().platform_handle());
  463. // |count| and |get_default| chosen impirically so that
  464. // time_constraints_buffer[0] would store the last constraints that were
  465. // applied.
  466. const int kPolicyCount = 32;
  467. thread_time_constraint_policy_data_t time_constraints_buffer[kPolicyCount];
  468. mach_msg_type_number_t count = kPolicyCount;
  469. boolean_t get_default = 0;
  470. kern_return_t result = thread_policy_get(
  471. mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
  472. reinterpret_cast<thread_policy_t>(time_constraints_buffer), &count,
  473. &get_default);
  474. EXPECT_EQ(result, KERN_SUCCESS);
  475. const thread_time_constraint_policy_data_t& time_constraints =
  476. time_constraints_buffer[0];
  477. mach_timebase_info_data_t tb_info;
  478. mach_timebase_info(&tb_info);
  479. if (FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac) &&
  480. #if BUILDFLAG(IS_MAC)
  481. !mac::IsOS10_14() && // Should not be applied on 10.14.
  482. #endif
  483. !realtime_period_.is_zero()) {
  484. uint32_t abs_realtime_period = saturated_cast<uint32_t>(
  485. realtime_period_.InNanoseconds() *
  486. (static_cast<double>(tb_info.denom) / tb_info.numer));
  487. EXPECT_EQ(time_constraints.period, abs_realtime_period);
  488. EXPECT_EQ(
  489. time_constraints.computation,
  490. static_cast<uint32_t>(abs_realtime_period *
  491. kOptimizedRealtimeThreadingMacBusy.Get()));
  492. EXPECT_EQ(
  493. time_constraints.constraint,
  494. static_cast<uint32_t>(abs_realtime_period *
  495. kOptimizedRealtimeThreadingMacBusyLimit.Get()));
  496. EXPECT_EQ(time_constraints.preemptible,
  497. kOptimizedRealtimeThreadingMacPreemptible.Get());
  498. } else {
  499. // Old-style empirical values.
  500. const double kTimeQuantum = 2.9;
  501. const double kAudioTimeNeeded = 0.75 * kTimeQuantum;
  502. const double kMaxTimeAllowed = 0.85 * kTimeQuantum;
  503. // Get the conversion factor from milliseconds to absolute time
  504. // which is what the time-constraints returns.
  505. double ms_to_abs_time = double(tb_info.denom) / tb_info.numer * 1000000;
  506. EXPECT_EQ(time_constraints.period,
  507. saturated_cast<uint32_t>(kTimeQuantum * ms_to_abs_time));
  508. EXPECT_EQ(time_constraints.computation,
  509. saturated_cast<uint32_t>(kAudioTimeNeeded * ms_to_abs_time));
  510. EXPECT_EQ(time_constraints.constraint,
  511. saturated_cast<uint32_t>(kMaxTimeAllowed * ms_to_abs_time));
  512. EXPECT_FALSE(time_constraints.preemptible);
  513. }
  514. }
  515. const TimeDelta realtime_period_;
  516. };
  517. class RealtimePlatformThreadTest
  518. : public testing::TestWithParam<
  519. std::tuple<bool, FieldTrialParams, TimeDelta>> {
  520. protected:
  521. void VerifyRealtimeConfig(TimeDelta period) {
  522. RealtimeTestThread thread(period);
  523. PlatformThreadHandle handle;
  524. ASSERT_FALSE(thread.IsRunning());
  525. ASSERT_TRUE(PlatformThread::CreateWithType(0, &thread, &handle,
  526. ThreadType::kRealtimeAudio));
  527. thread.WaitForTerminationReady();
  528. ASSERT_TRUE(thread.IsRunning());
  529. thread.MarkForTermination();
  530. PlatformThread::Join(handle);
  531. ASSERT_FALSE(thread.IsRunning());
  532. }
  533. };
  534. TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMac) {
  535. test::ScopedFeatureList feature_list;
  536. if (std::get<0>(GetParam())) {
  537. feature_list.InitAndEnableFeatureWithParameters(
  538. kOptimizedRealtimeThreadingMac, std::get<1>(GetParam()));
  539. } else {
  540. feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac);
  541. }
  542. PlatformThread::InitializeOptimizedRealtimeThreadingFeature();
  543. VerifyRealtimeConfig(std::get<2>(GetParam()));
  544. }
  545. INSTANTIATE_TEST_SUITE_P(
  546. RealtimePlatformThreadTest,
  547. RealtimePlatformThreadTest,
  548. testing::Combine(
  549. testing::Bool(),
  550. testing::Values(
  551. FieldTrialParams{
  552. {kOptimizedRealtimeThreadingMacPreemptible.name, "true"}},
  553. FieldTrialParams{
  554. {kOptimizedRealtimeThreadingMacPreemptible.name, "false"}},
  555. FieldTrialParams{
  556. {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
  557. {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.75"}},
  558. FieldTrialParams{
  559. {kOptimizedRealtimeThreadingMacBusy.name, "0.7"},
  560. {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.7"}},
  561. FieldTrialParams{
  562. {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
  563. {kOptimizedRealtimeThreadingMacBusyLimit.name, "1.0"}}),
  564. testing::Values(TimeDelta(),
  565. Seconds(256.0 / 48000),
  566. Milliseconds(5),
  567. Milliseconds(10),
  568. Seconds(1024.0 / 44100),
  569. Seconds(1024.0 / 16000))));
  570. } // namespace
  571. #endif // BUILDFLAG(IS_APPLE)
  572. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  573. namespace {
  574. bool IsTidCacheCorrect() {
  575. return PlatformThread::CurrentId() == syscall(__NR_gettid);
  576. }
  577. void* CheckTidCacheCorrectWrapper(void*) {
  578. CHECK(IsTidCacheCorrect());
  579. return nullptr;
  580. }
  581. void CreatePthreadToCheckCache() {
  582. pthread_t thread_id;
  583. pthread_create(&thread_id, nullptr, CheckTidCacheCorrectWrapper, nullptr);
  584. pthread_join(thread_id, nullptr);
  585. }
  586. // This test must use raw pthreads and fork() to avoid calls from //base to
  587. // PlatformThread::CurrentId(), as the ordering of calls is important to the
  588. // test.
  589. void TestTidCacheCorrect(bool main_thread_accesses_cache_first) {
  590. EXPECT_TRUE(IsTidCacheCorrect());
  591. CreatePthreadToCheckCache();
  592. // Now fork a process and make sure the TID cache gets correctly updated on
  593. // both its main thread and a child thread.
  594. pid_t child_pid = fork();
  595. ASSERT_GE(child_pid, 0);
  596. if (child_pid == 0) {
  597. // In the child.
  598. if (main_thread_accesses_cache_first) {
  599. if (!IsTidCacheCorrect())
  600. _exit(1);
  601. }
  602. // Access the TID cache on another thread and make sure the cached value is
  603. // correct.
  604. CreatePthreadToCheckCache();
  605. if (!main_thread_accesses_cache_first) {
  606. // Make sure the main thread's cache is correct even though another thread
  607. // accessed the cache first.
  608. if (!IsTidCacheCorrect())
  609. _exit(1);
  610. }
  611. _exit(0);
  612. }
  613. int status;
  614. ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid);
  615. ASSERT_TRUE(WIFEXITED(status));
  616. ASSERT_EQ(WEXITSTATUS(status), 0);
  617. }
  618. TEST(PlatformThreadTidCacheTest, MainThreadFirst) {
  619. TestTidCacheCorrect(true);
  620. }
  621. TEST(PlatformThreadTidCacheTest, MainThreadSecond) {
  622. TestTidCacheCorrect(false);
  623. }
  624. } // namespace
  625. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  626. } // namespace base