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