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