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