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