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