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