• 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.
429   constexpr bool kCanIncreasePriority = false;
430 #else
431   constexpr bool kCanIncreasePriority = true;
432 #endif
433 
434   for (auto type : kAllThreadTypes) {
435     EXPECT_TRUE(PlatformThread::CanChangeThreadType(type, type));
436   }
437 #if BUILDFLAG(IS_FUCHSIA)
438   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
439                                                    ThreadType::kUtility));
440   EXPECT_FALSE(PlatformThread::CanChangeThreadType(
441       ThreadType::kBackground, ThreadType::kResourceEfficient));
442   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
443                                                    ThreadType::kDefault));
444   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
445                                                    ThreadType::kCompositing));
446   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
447                                                    ThreadType::kBackground));
448   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
449                                                    ThreadType::kBackground));
450 #else
451   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
452                                                 ThreadType::kUtility),
453             kCanIncreasePriority);
454   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
455                                                 ThreadType::kResourceEfficient),
456             kCanIncreasePriority);
457   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
458                                                 ThreadType::kDefault),
459             kCanIncreasePriority);
460   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
461                                                 ThreadType::kCompositing),
462             kCanIncreasePriority);
463   EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDefault,
464                                                   ThreadType::kBackground));
465   EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
466                                                   ThreadType::kBackground));
467 #endif
468   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
469                                                 ThreadType::kDisplayCritical),
470             kCanIncreasePriority);
471   EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
472                                                 ThreadType::kRealtimeAudio),
473             kCanIncreasePriority);
474 #if BUILDFLAG(IS_FUCHSIA)
475   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
476                                                    ThreadType::kBackground));
477   EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
478                                                    ThreadType::kBackground));
479 #else
480   EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kDisplayCritical,
481                                                   ThreadType::kBackground));
482   EXPECT_TRUE(PlatformThread::CanChangeThreadType(ThreadType::kRealtimeAudio,
483                                                   ThreadType::kBackground));
484 #endif
485 }
486 
TEST(PlatformThreadTest,SetCurrentThreadTypeTest)487 TEST(PlatformThreadTest, SetCurrentThreadTypeTest) {
488   TestPriorityResultingFromThreadType(ThreadType::kBackground,
489                                       ThreadPriorityForTest::kBackground);
490   TestPriorityResultingFromThreadType(ThreadType::kUtility,
491                                       ThreadPriorityForTest::kUtility);
492 #if BUILDFLAG(IS_APPLE)
493   TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
494                                       ThreadPriorityForTest::kUtility);
495 #else
496   TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
497                                       ThreadPriorityForTest::kNormal);
498 #endif  // BUILDFLAG(IS_APPLE)
499   TestPriorityResultingFromThreadType(ThreadType::kDefault,
500                                       ThreadPriorityForTest::kNormal);
501 #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
502   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
503                                       ThreadPriorityForTest::kDisplay);
504 #if BUILDFLAG(IS_WIN)
505   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
506                                       MessagePumpType::UI,
507                                       ThreadPriorityForTest::kNormal);
508 #else
509   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
510                                       MessagePumpType::UI,
511                                       ThreadPriorityForTest::kDisplay);
512 #endif  // BUILDFLAG(IS_WIN)
513   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
514                                       MessagePumpType::IO,
515                                       ThreadPriorityForTest::kDisplay);
516 #else  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_FUCHSIA)
517   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
518                                       ThreadPriorityForTest::kNormal);
519   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
520                                       MessagePumpType::UI,
521                                       ThreadPriorityForTest::kNormal);
522   TestPriorityResultingFromThreadType(ThreadType::kCompositing,
523                                       MessagePumpType::IO,
524                                       ThreadPriorityForTest::kNormal);
525 #endif
526   TestPriorityResultingFromThreadType(ThreadType::kDisplayCritical,
527                                       ThreadPriorityForTest::kDisplay);
528   TestPriorityResultingFromThreadType(ThreadType::kRealtimeAudio,
529                                       ThreadPriorityForTest::kRealtimeAudio);
530 }
531 
TEST(PlatformThreadTest,SetHugeThreadName)532 TEST(PlatformThreadTest, SetHugeThreadName) {
533   // Construct an excessively long thread name.
534   std::string long_name(1024, 'a');
535 
536   // SetName has no return code, so just verify that implementations
537   // don't [D]CHECK().
538   PlatformThread::SetName(long_name);
539 }
540 
TEST(PlatformThreadTest,GetDefaultThreadStackSize)541 TEST(PlatformThreadTest, GetDefaultThreadStackSize) {
542   size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
543 #if BUILDFLAG(IS_IOS) && BUILDFLAG(USE_BLINK)
544   EXPECT_EQ(1024u * 1024u, stack_size);
545 #elif BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA) ||      \
546     ((BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && defined(__GLIBC__) && \
547      !defined(THREAD_SANITIZER)) ||                                           \
548     (BUILDFLAG(IS_ANDROID) && !defined(ADDRESS_SANITIZER))
549   EXPECT_EQ(0u, stack_size);
550 #else
551   EXPECT_GT(stack_size, 0u);
552   EXPECT_LT(stack_size, 20u * (1 << 20));
553 #endif
554 }
555 
556 #if BUILDFLAG(IS_APPLE)
557 
558 namespace {
559 
560 class RealtimeTestThread : public FunctionTestThread {
561  public:
RealtimeTestThread(TimeDelta realtime_period)562   explicit RealtimeTestThread(TimeDelta realtime_period)
563       : realtime_period_(realtime_period) {}
564   ~RealtimeTestThread() override = default;
565 
566  private:
567   RealtimeTestThread(const RealtimeTestThread&) = delete;
568   RealtimeTestThread& operator=(const RealtimeTestThread&) = delete;
569 
GetRealtimePeriod()570   TimeDelta GetRealtimePeriod() final { return realtime_period_; }
571 
572   // Verifies the realtime thead configuration.
RunTest()573   void RunTest() override {
574     EXPECT_EQ(PlatformThread::GetCurrentThreadType(),
575               ThreadType::kRealtimeAudio);
576 
577     mach_port_t mach_thread_id = pthread_mach_thread_np(
578         PlatformThread::CurrentHandle().platform_handle());
579 
580     // |count| and |get_default| chosen impirically so that
581     // time_constraints_buffer[0] would store the last constraints that were
582     // applied.
583     const int kPolicyCount = 32;
584     thread_time_constraint_policy_data_t time_constraints_buffer[kPolicyCount];
585     mach_msg_type_number_t count = kPolicyCount;
586     boolean_t get_default = 0;
587 
588     kern_return_t result = thread_policy_get(
589         mach_thread_id, THREAD_TIME_CONSTRAINT_POLICY,
590         reinterpret_cast<thread_policy_t>(time_constraints_buffer), &count,
591         &get_default);
592 
593     EXPECT_EQ(result, KERN_SUCCESS);
594 
595     const thread_time_constraint_policy_data_t& time_constraints =
596         time_constraints_buffer[0];
597 
598     mach_timebase_info_data_t tb_info;
599     mach_timebase_info(&tb_info);
600 
601     if (FeatureList::IsEnabled(kOptimizedRealtimeThreadingMac) &&
602 #if BUILDFLAG(IS_MAC)
603         !mac::IsOS10_14() &&  // Should not be applied on 10.14.
604 #endif
605         !realtime_period_.is_zero()) {
606       uint32_t abs_realtime_period = saturated_cast<uint32_t>(
607           realtime_period_.InNanoseconds() *
608           (static_cast<double>(tb_info.denom) / tb_info.numer));
609 
610       EXPECT_EQ(time_constraints.period, abs_realtime_period);
611       EXPECT_EQ(
612           time_constraints.computation,
613           static_cast<uint32_t>(abs_realtime_period *
614                                 kOptimizedRealtimeThreadingMacBusy.Get()));
615       EXPECT_EQ(
616           time_constraints.constraint,
617           static_cast<uint32_t>(abs_realtime_period *
618                                 kOptimizedRealtimeThreadingMacBusyLimit.Get()));
619       EXPECT_EQ(time_constraints.preemptible,
620                 kOptimizedRealtimeThreadingMacPreemptible.Get());
621     } else {
622       // Old-style empirical values.
623       const double kTimeQuantum = 2.9;
624       const double kAudioTimeNeeded = 0.75 * kTimeQuantum;
625       const double kMaxTimeAllowed = 0.85 * kTimeQuantum;
626 
627       // Get the conversion factor from milliseconds to absolute time
628       // which is what the time-constraints returns.
629       double ms_to_abs_time = double(tb_info.denom) / tb_info.numer * 1000000;
630 
631       EXPECT_EQ(time_constraints.period,
632                 saturated_cast<uint32_t>(kTimeQuantum * ms_to_abs_time));
633       EXPECT_EQ(time_constraints.computation,
634                 saturated_cast<uint32_t>(kAudioTimeNeeded * ms_to_abs_time));
635       EXPECT_EQ(time_constraints.constraint,
636                 saturated_cast<uint32_t>(kMaxTimeAllowed * ms_to_abs_time));
637       EXPECT_FALSE(time_constraints.preemptible);
638     }
639   }
640 
641   const TimeDelta realtime_period_;
642 };
643 
644 class RealtimePlatformThreadTest
645     : public testing::TestWithParam<
646           std::tuple<bool, FieldTrialParams, TimeDelta>> {
647  protected:
VerifyRealtimeConfig(TimeDelta period)648   void VerifyRealtimeConfig(TimeDelta period) {
649     RealtimeTestThread thread(period);
650     PlatformThreadHandle handle;
651 
652     ASSERT_FALSE(thread.IsRunning());
653     ASSERT_TRUE(PlatformThread::CreateWithType(0, &thread, &handle,
654                                                ThreadType::kRealtimeAudio));
655     thread.WaitForTerminationReady();
656     ASSERT_TRUE(thread.IsRunning());
657 
658     thread.MarkForTermination();
659     PlatformThread::Join(handle);
660     ASSERT_FALSE(thread.IsRunning());
661   }
662 };
663 
TEST_P(RealtimePlatformThreadTest,RealtimeAudioConfigMac)664 TEST_P(RealtimePlatformThreadTest, RealtimeAudioConfigMac) {
665   test::ScopedFeatureList feature_list;
666   if (std::get<0>(GetParam())) {
667     feature_list.InitAndEnableFeatureWithParameters(
668         kOptimizedRealtimeThreadingMac, std::get<1>(GetParam()));
669   } else {
670     feature_list.InitAndDisableFeature(kOptimizedRealtimeThreadingMac);
671   }
672 
673   PlatformThread::InitFeaturesPostFieldTrial();
674   VerifyRealtimeConfig(std::get<2>(GetParam()));
675 }
676 
677 INSTANTIATE_TEST_SUITE_P(
678     RealtimePlatformThreadTest,
679     RealtimePlatformThreadTest,
680     testing::Combine(
681         testing::Bool(),
682         testing::Values(
683             FieldTrialParams{
684                 {kOptimizedRealtimeThreadingMacPreemptible.name, "true"}},
685             FieldTrialParams{
686                 {kOptimizedRealtimeThreadingMacPreemptible.name, "false"}},
687             FieldTrialParams{
688                 {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
689                 {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.75"}},
690             FieldTrialParams{
691                 {kOptimizedRealtimeThreadingMacBusy.name, "0.7"},
692                 {kOptimizedRealtimeThreadingMacBusyLimit.name, "0.7"}},
693             FieldTrialParams{
694                 {kOptimizedRealtimeThreadingMacBusy.name, "0.5"},
695                 {kOptimizedRealtimeThreadingMacBusyLimit.name, "1.0"}}),
696         testing::Values(TimeDelta(),
697                         Seconds(256.0 / 48000),
698                         Milliseconds(5),
699                         Milliseconds(10),
700                         Seconds(1024.0 / 44100),
701                         Seconds(1024.0 / 16000))));
702 
703 }  // namespace
704 
705 #endif  // BUILDFLAG(IS_APPLE)
706 
707 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
708 
709 namespace {
710 
IsTidCacheCorrect()711 bool IsTidCacheCorrect() {
712   return PlatformThread::CurrentId() == syscall(__NR_gettid);
713 }
714 
CheckTidCacheCorrectWrapper(void *)715 void* CheckTidCacheCorrectWrapper(void*) {
716   CHECK(IsTidCacheCorrect());
717   return nullptr;
718 }
719 
CreatePthreadToCheckCache()720 void CreatePthreadToCheckCache() {
721   pthread_t thread_id;
722   pthread_create(&thread_id, nullptr, CheckTidCacheCorrectWrapper, nullptr);
723   pthread_join(thread_id, nullptr);
724 }
725 
726 // This test must use raw pthreads and fork() to avoid calls from //base to
727 // PlatformThread::CurrentId(), as the ordering of calls is important to the
728 // test.
TestTidCacheCorrect(bool main_thread_accesses_cache_first)729 void TestTidCacheCorrect(bool main_thread_accesses_cache_first) {
730   EXPECT_TRUE(IsTidCacheCorrect());
731 
732   CreatePthreadToCheckCache();
733 
734   // Now fork a process and make sure the TID cache gets correctly updated on
735   // both its main thread and a child thread.
736   pid_t child_pid = fork();
737   ASSERT_GE(child_pid, 0);
738 
739   if (child_pid == 0) {
740     // In the child.
741     if (main_thread_accesses_cache_first) {
742       if (!IsTidCacheCorrect())
743         _exit(1);
744     }
745 
746     // Access the TID cache on another thread and make sure the cached value is
747     // correct.
748     CreatePthreadToCheckCache();
749 
750     if (!main_thread_accesses_cache_first) {
751       // Make sure the main thread's cache is correct even though another thread
752       // accessed the cache first.
753       if (!IsTidCacheCorrect())
754         _exit(1);
755     }
756 
757     _exit(0);
758   }
759 
760   int status;
761   ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid);
762   ASSERT_TRUE(WIFEXITED(status));
763   ASSERT_EQ(WEXITSTATUS(status), 0);
764 }
765 
TEST(PlatformThreadTidCacheTest,MainThreadFirst)766 TEST(PlatformThreadTidCacheTest, MainThreadFirst) {
767   TestTidCacheCorrect(true);
768 }
769 
TEST(PlatformThreadTidCacheTest,MainThreadSecond)770 TEST(PlatformThreadTidCacheTest, MainThreadSecond) {
771   TestTidCacheCorrect(false);
772 }
773 
774 }  // namespace
775 
776 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
777 
778 }  // namespace base
779