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