1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <stddef.h>
6
7 #include "base/compiler_specific.h"
8 #include "base/macros.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/platform_thread.h"
11 #include "build/build_config.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 #if defined(OS_POSIX)
15 #include "base/threading/platform_thread_internal_posix.h"
16 #elif defined(OS_WIN)
17 #include <windows.h>
18 #endif
19
20 namespace base {
21
22 // Trivial tests that thread runs and doesn't crash on create, join, or detach -
23
24 namespace {
25
26 class TrivialThread : public PlatformThread::Delegate {
27 public:
TrivialThread()28 TrivialThread() : run_event_(WaitableEvent::ResetPolicy::MANUAL,
29 WaitableEvent::InitialState::NOT_SIGNALED) {}
30
ThreadMain()31 void ThreadMain() override { run_event_.Signal(); }
32
run_event()33 WaitableEvent& run_event() { return run_event_; }
34
35 private:
36 WaitableEvent run_event_;
37
38 DISALLOW_COPY_AND_ASSIGN(TrivialThread);
39 };
40
41 } // namespace
42
TEST(PlatformThreadTest,TrivialJoin)43 TEST(PlatformThreadTest, TrivialJoin) {
44 TrivialThread thread;
45 PlatformThreadHandle handle;
46
47 ASSERT_FALSE(thread.run_event().IsSignaled());
48 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
49 PlatformThread::Join(handle);
50 ASSERT_TRUE(thread.run_event().IsSignaled());
51 }
52
TEST(PlatformThreadTest,TrivialJoinTimesTen)53 TEST(PlatformThreadTest, TrivialJoinTimesTen) {
54 TrivialThread thread[10];
55 PlatformThreadHandle handle[arraysize(thread)];
56
57 for (size_t n = 0; n < arraysize(thread); n++)
58 ASSERT_FALSE(thread[n].run_event().IsSignaled());
59 for (size_t n = 0; n < arraysize(thread); n++)
60 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
61 for (size_t n = 0; n < arraysize(thread); n++)
62 PlatformThread::Join(handle[n]);
63 for (size_t n = 0; n < arraysize(thread); n++)
64 ASSERT_TRUE(thread[n].run_event().IsSignaled());
65 }
66
67 // The following detach tests are by nature racy. The run_event approximates the
68 // end and termination of the thread, but threads could persist shortly after
69 // the test completes.
TEST(PlatformThreadTest,TrivialDetach)70 TEST(PlatformThreadTest, TrivialDetach) {
71 TrivialThread thread;
72 PlatformThreadHandle handle;
73
74 ASSERT_FALSE(thread.run_event().IsSignaled());
75 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
76 PlatformThread::Detach(handle);
77 thread.run_event().Wait();
78 }
79
TEST(PlatformThreadTest,TrivialDetachTimesTen)80 TEST(PlatformThreadTest, TrivialDetachTimesTen) {
81 TrivialThread thread[10];
82 PlatformThreadHandle handle[arraysize(thread)];
83
84 for (size_t n = 0; n < arraysize(thread); n++)
85 ASSERT_FALSE(thread[n].run_event().IsSignaled());
86 for (size_t n = 0; n < arraysize(thread); n++) {
87 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
88 PlatformThread::Detach(handle[n]);
89 }
90 for (size_t n = 0; n < arraysize(thread); n++)
91 thread[n].run_event().Wait();
92 }
93
94 // Tests of basic thread functions ---------------------------------------------
95
96 namespace {
97
98 class FunctionTestThread : public PlatformThread::Delegate {
99 public:
FunctionTestThread()100 FunctionTestThread()
101 : thread_id_(kInvalidThreadId),
102 termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
103 WaitableEvent::InitialState::NOT_SIGNALED),
104 terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
105 WaitableEvent::InitialState::NOT_SIGNALED),
106 done_(false) {}
~FunctionTestThread()107 ~FunctionTestThread() override {
108 EXPECT_TRUE(terminate_thread_.IsSignaled())
109 << "Need to mark thread for termination and join the underlying thread "
110 << "before destroying a FunctionTestThread as it owns the "
111 << "WaitableEvent blocking the underlying thread's main.";
112 }
113
114 // Grabs |thread_id_|, runs an optional test on that thread, signals
115 // |termination_ready_|, and then waits for |terminate_thread_| to be
116 // signaled before exiting.
ThreadMain()117 void ThreadMain() override {
118 thread_id_ = PlatformThread::CurrentId();
119 EXPECT_NE(thread_id_, kInvalidThreadId);
120
121 // Make sure that the thread ID is the same across calls.
122 EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
123
124 // Run extra tests.
125 RunTest();
126
127 termination_ready_.Signal();
128 terminate_thread_.Wait();
129
130 done_ = true;
131 }
132
thread_id() const133 PlatformThreadId thread_id() const {
134 EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
135 return thread_id_;
136 }
137
IsRunning() const138 bool IsRunning() const {
139 return termination_ready_.IsSignaled() && !done_;
140 }
141
142 // Blocks until this thread is started and ready to be terminated.
WaitForTerminationReady()143 void WaitForTerminationReady() { termination_ready_.Wait(); }
144
145 // Marks this thread for termination (callers must then join this thread to be
146 // guaranteed of termination).
MarkForTermination()147 void MarkForTermination() { terminate_thread_.Signal(); }
148
149 private:
150 // Runs an optional test on the newly created thread.
RunTest()151 virtual void RunTest() {}
152
153 PlatformThreadId thread_id_;
154
155 mutable WaitableEvent termination_ready_;
156 WaitableEvent terminate_thread_;
157 bool done_;
158
159 DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
160 };
161
162 } // namespace
163
TEST(PlatformThreadTest,Function)164 TEST(PlatformThreadTest, Function) {
165 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
166
167 FunctionTestThread thread;
168 PlatformThreadHandle handle;
169
170 ASSERT_FALSE(thread.IsRunning());
171 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
172 thread.WaitForTerminationReady();
173 ASSERT_TRUE(thread.IsRunning());
174 EXPECT_NE(thread.thread_id(), main_thread_id);
175
176 thread.MarkForTermination();
177 PlatformThread::Join(handle);
178 ASSERT_FALSE(thread.IsRunning());
179
180 // Make sure that the thread ID is the same across calls.
181 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
182 }
183
TEST(PlatformThreadTest,FunctionTimesTen)184 TEST(PlatformThreadTest, FunctionTimesTen) {
185 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
186
187 FunctionTestThread thread[10];
188 PlatformThreadHandle handle[arraysize(thread)];
189
190 for (size_t n = 0; n < arraysize(thread); n++)
191 ASSERT_FALSE(thread[n].IsRunning());
192
193 for (size_t n = 0; n < arraysize(thread); n++)
194 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
195 for (size_t n = 0; n < arraysize(thread); n++)
196 thread[n].WaitForTerminationReady();
197
198 for (size_t n = 0; n < arraysize(thread); n++) {
199 ASSERT_TRUE(thread[n].IsRunning());
200 EXPECT_NE(thread[n].thread_id(), main_thread_id);
201
202 // Make sure no two threads get the same ID.
203 for (size_t i = 0; i < n; ++i) {
204 EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
205 }
206 }
207
208 for (size_t n = 0; n < arraysize(thread); n++)
209 thread[n].MarkForTermination();
210 for (size_t n = 0; n < arraysize(thread); n++)
211 PlatformThread::Join(handle[n]);
212 for (size_t n = 0; n < arraysize(thread); n++)
213 ASSERT_FALSE(thread[n].IsRunning());
214
215 // Make sure that the thread ID is the same across calls.
216 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
217 }
218
219 namespace {
220
221 const ThreadPriority kThreadPriorityTestValues[] = {
222 // The order should be higher to lower to cover as much cases as possible on
223 // Linux trybots running without CAP_SYS_NICE permission.
224 #if !defined(OS_ANDROID)
225 // PlatformThread::GetCurrentThreadPriority() on Android does not support
226 // REALTIME_AUDIO case. See http://crbug.com/505474.
227 ThreadPriority::REALTIME_AUDIO,
228 #endif
229 ThreadPriority::DISPLAY,
230 // This redundant BACKGROUND priority is to test backgrounding from other
231 // priorities, and unbackgrounding.
232 ThreadPriority::BACKGROUND,
233 ThreadPriority::NORMAL,
234 ThreadPriority::BACKGROUND};
235
236 class ThreadPriorityTestThread : public FunctionTestThread {
237 public:
ThreadPriorityTestThread(ThreadPriority priority)238 explicit ThreadPriorityTestThread(ThreadPriority priority)
239 : priority_(priority) {}
240 ~ThreadPriorityTestThread() override = default;
241
242 private:
RunTest()243 void RunTest() override {
244 // Confirm that the current thread's priority is as expected.
245 EXPECT_EQ(ThreadPriority::NORMAL,
246 PlatformThread::GetCurrentThreadPriority());
247
248 // Alter and verify the current thread's priority.
249 PlatformThread::SetCurrentThreadPriority(priority_);
250 EXPECT_EQ(priority_, PlatformThread::GetCurrentThreadPriority());
251 }
252
253 const ThreadPriority priority_;
254
255 DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
256 };
257
258 } // namespace
259
260 // Test changing a created thread's priority (which has different semantics on
261 // some platforms).
262 #if defined(OS_FUCHSIA)
263 // TODO(crbug.com/851759): Thread priorities are not implemented in Fuchsia.
264 #define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
265 #else
266 #define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
267 #endif
TEST(PlatformThreadTest,MAYBE_ThreadPriorityCurrentThread)268 TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
269 const bool increase_priority_allowed =
270 PlatformThread::CanIncreaseCurrentThreadPriority();
271
272 // Bump the priority in order to verify that new threads are started with normal
273 // priority. Skip this on Mac since this platform doesn't allow changing the
274 // priority of the main thread. Also skip this on platforms that don't allow
275 // increasing the priority of a thread.
276 #if !defined(OS_MACOSX)
277 if (increase_priority_allowed)
278 PlatformThread::SetCurrentThreadPriority(ThreadPriority::DISPLAY);
279 #endif
280
281 // Toggle each supported priority on the thread and confirm it affects it.
282 for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
283 if (!increase_priority_allowed &&
284 kThreadPriorityTestValues[i] >
285 PlatformThread::GetCurrentThreadPriority()) {
286 continue;
287 }
288
289 ThreadPriorityTestThread thread(kThreadPriorityTestValues[i]);
290 PlatformThreadHandle handle;
291
292 ASSERT_FALSE(thread.IsRunning());
293 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
294 thread.WaitForTerminationReady();
295 ASSERT_TRUE(thread.IsRunning());
296
297 thread.MarkForTermination();
298 PlatformThread::Join(handle);
299 ASSERT_FALSE(thread.IsRunning());
300 }
301 }
302
303 // This tests internal PlatformThread APIs used under some POSIX platforms,
304 // with the exception of Mac OS X, iOS and Fuchsia.
305 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) && \
306 !defined(OS_FUCHSIA)
TEST(PlatformThreadTest,GetNiceValueToThreadPriority)307 TEST(PlatformThreadTest, GetNiceValueToThreadPriority) {
308 using internal::NiceValueToThreadPriority;
309 using internal::kThreadPriorityToNiceValueMap;
310
311 EXPECT_EQ(ThreadPriority::BACKGROUND,
312 kThreadPriorityToNiceValueMap[0].priority);
313 EXPECT_EQ(ThreadPriority::NORMAL,
314 kThreadPriorityToNiceValueMap[1].priority);
315 EXPECT_EQ(ThreadPriority::DISPLAY,
316 kThreadPriorityToNiceValueMap[2].priority);
317 EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
318 kThreadPriorityToNiceValueMap[3].priority);
319
320 static const int kBackgroundNiceValue =
321 kThreadPriorityToNiceValueMap[0].nice_value;
322 static const int kNormalNiceValue =
323 kThreadPriorityToNiceValueMap[1].nice_value;
324 static const int kDisplayNiceValue =
325 kThreadPriorityToNiceValueMap[2].nice_value;
326 static const int kRealtimeAudioNiceValue =
327 kThreadPriorityToNiceValueMap[3].nice_value;
328
329 // The tests below assume the nice values specified in the map are within
330 // the range below (both ends exclusive).
331 static const int kHighestNiceValue = 19;
332 static const int kLowestNiceValue = -20;
333
334 EXPECT_GT(kHighestNiceValue, kBackgroundNiceValue);
335 EXPECT_GT(kBackgroundNiceValue, kNormalNiceValue);
336 EXPECT_GT(kNormalNiceValue, kDisplayNiceValue);
337 EXPECT_GT(kDisplayNiceValue, kRealtimeAudioNiceValue);
338 EXPECT_GT(kRealtimeAudioNiceValue, kLowestNiceValue);
339
340 EXPECT_EQ(ThreadPriority::BACKGROUND,
341 NiceValueToThreadPriority(kHighestNiceValue));
342 EXPECT_EQ(ThreadPriority::BACKGROUND,
343 NiceValueToThreadPriority(kBackgroundNiceValue + 1));
344 EXPECT_EQ(ThreadPriority::BACKGROUND,
345 NiceValueToThreadPriority(kBackgroundNiceValue));
346 EXPECT_EQ(ThreadPriority::BACKGROUND,
347 NiceValueToThreadPriority(kNormalNiceValue + 1));
348 EXPECT_EQ(ThreadPriority::NORMAL,
349 NiceValueToThreadPriority(kNormalNiceValue));
350 EXPECT_EQ(ThreadPriority::NORMAL,
351 NiceValueToThreadPriority(kDisplayNiceValue + 1));
352 EXPECT_EQ(ThreadPriority::DISPLAY,
353 NiceValueToThreadPriority(kDisplayNiceValue));
354 EXPECT_EQ(ThreadPriority::DISPLAY,
355 NiceValueToThreadPriority(kRealtimeAudioNiceValue + 1));
356 EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
357 NiceValueToThreadPriority(kRealtimeAudioNiceValue));
358 EXPECT_EQ(ThreadPriority::REALTIME_AUDIO,
359 NiceValueToThreadPriority(kLowestNiceValue));
360 }
361 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) &&
362 // !defined(OS_FUCHSIA)
363
TEST(PlatformThreadTest,SetHugeThreadName)364 TEST(PlatformThreadTest, SetHugeThreadName) {
365 // Construct an excessively long thread name.
366 std::string long_name(1024, 'a');
367
368 // SetName has no return code, so just verify that implementations
369 // don't [D]CHECK().
370 PlatformThread::SetName(long_name);
371 }
372
373 } // namespace base
374