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