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 #elif defined(OS_WIN)
18 #include <windows.h>
19 #endif
20
21 namespace base {
22
23 // Trivial tests that thread runs and doesn't crash on create and join ---------
24
25 namespace {
26
27 class TrivialThread : public PlatformThread::Delegate {
28 public:
TrivialThread()29 TrivialThread() : did_run_(false) {}
30
ThreadMain()31 void ThreadMain() override { did_run_ = true; }
32
did_run() const33 bool did_run() const { return did_run_; }
34
35 private:
36 bool did_run_;
37
38 DISALLOW_COPY_AND_ASSIGN(TrivialThread);
39 };
40
41 } // namespace
42
TEST(PlatformThreadTest,Trivial)43 TEST(PlatformThreadTest, Trivial) {
44 TrivialThread thread;
45 PlatformThreadHandle handle;
46
47 ASSERT_FALSE(thread.did_run());
48 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
49 PlatformThread::Join(handle);
50 ASSERT_TRUE(thread.did_run());
51 }
52
TEST(PlatformThreadTest,TrivialTimesTen)53 TEST(PlatformThreadTest, TrivialTimesTen) {
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].did_run());
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].did_run());
65 }
66
67 // Tests of basic thread functions ---------------------------------------------
68
69 namespace {
70
71 class FunctionTestThread : public PlatformThread::Delegate {
72 public:
FunctionTestThread()73 FunctionTestThread()
74 : thread_id_(kInvalidThreadId),
75 termination_ready_(true, false),
76 terminate_thread_(true, false),
77 done_(false) {}
~FunctionTestThread()78 ~FunctionTestThread() override {
79 EXPECT_TRUE(terminate_thread_.IsSignaled())
80 << "Need to mark thread for termination and join the underlying thread "
81 << "before destroying a FunctionTestThread as it owns the "
82 << "WaitableEvent blocking the underlying thread's main.";
83 }
84
85 // Grabs |thread_id_|, runs an optional test on that thread, signals
86 // |termination_ready_|, and then waits for |terminate_thread_| to be
87 // signaled before exiting.
ThreadMain()88 void ThreadMain() override {
89 thread_id_ = PlatformThread::CurrentId();
90 EXPECT_NE(thread_id_, kInvalidThreadId);
91
92 // Make sure that the thread ID is the same across calls.
93 EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
94
95 // Run extra tests.
96 RunTest();
97
98 termination_ready_.Signal();
99 terminate_thread_.Wait();
100
101 done_ = true;
102 }
103
thread_id() const104 PlatformThreadId thread_id() const {
105 EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
106 return thread_id_;
107 }
108
IsRunning() const109 bool IsRunning() const {
110 return termination_ready_.IsSignaled() && !done_;
111 }
112
113 // Blocks until this thread is started and ready to be terminated.
WaitForTerminationReady()114 void WaitForTerminationReady() { termination_ready_.Wait(); }
115
116 // Marks this thread for termination (callers must then join this thread to be
117 // guaranteed of termination).
MarkForTermination()118 void MarkForTermination() { terminate_thread_.Signal(); }
119
120 private:
121 // Runs an optional test on the newly created thread.
RunTest()122 virtual void RunTest() {}
123
124 PlatformThreadId thread_id_;
125
126 mutable WaitableEvent termination_ready_;
127 WaitableEvent terminate_thread_;
128 bool done_;
129
130 DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
131 };
132
133 } // namespace
134
TEST(PlatformThreadTest,Function)135 TEST(PlatformThreadTest, Function) {
136 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
137
138 FunctionTestThread thread;
139 PlatformThreadHandle handle;
140
141 ASSERT_FALSE(thread.IsRunning());
142 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
143 thread.WaitForTerminationReady();
144 ASSERT_TRUE(thread.IsRunning());
145 EXPECT_NE(thread.thread_id(), main_thread_id);
146
147 thread.MarkForTermination();
148 PlatformThread::Join(handle);
149 ASSERT_FALSE(thread.IsRunning());
150
151 // Make sure that the thread ID is the same across calls.
152 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
153 }
154
TEST(PlatformThreadTest,FunctionTimesTen)155 TEST(PlatformThreadTest, FunctionTimesTen) {
156 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
157
158 FunctionTestThread thread[10];
159 PlatformThreadHandle handle[arraysize(thread)];
160
161 for (size_t n = 0; n < arraysize(thread); n++)
162 ASSERT_FALSE(thread[n].IsRunning());
163
164 for (size_t n = 0; n < arraysize(thread); n++)
165 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
166 for (size_t n = 0; n < arraysize(thread); n++)
167 thread[n].WaitForTerminationReady();
168
169 for (size_t n = 0; n < arraysize(thread); n++) {
170 ASSERT_TRUE(thread[n].IsRunning());
171 EXPECT_NE(thread[n].thread_id(), main_thread_id);
172
173 // Make sure no two threads get the same ID.
174 for (size_t i = 0; i < n; ++i) {
175 EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
176 }
177 }
178
179 for (size_t n = 0; n < arraysize(thread); n++)
180 thread[n].MarkForTermination();
181 for (size_t n = 0; n < arraysize(thread); n++)
182 PlatformThread::Join(handle[n]);
183 for (size_t n = 0; n < arraysize(thread); n++)
184 ASSERT_FALSE(thread[n].IsRunning());
185
186 // Make sure that the thread ID is the same across calls.
187 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
188 }
189
190 namespace {
191
192 const ThreadPriority kThreadPriorityTestValues[] = {
193 // The order should be higher to lower to cover as much cases as possible on
194 // Linux trybots running without CAP_SYS_NICE permission.
195 #if !defined(OS_ANDROID)
196 // PlatformThread::GetCurrentThreadPriority() on Android does not support
197 // REALTIME_AUDIO case. See http://crbug.com/505474.
198 ThreadPriority::REALTIME_AUDIO,
199 #endif
200 ThreadPriority::DISPLAY,
201 // This redundant BACKGROUND priority is to test backgrounding from other
202 // priorities, and unbackgrounding.
203 ThreadPriority::BACKGROUND,
204 ThreadPriority::NORMAL,
205 ThreadPriority::BACKGROUND};
206
IsBumpingPriorityAllowed()207 bool IsBumpingPriorityAllowed() {
208 #if defined(OS_POSIX)
209 // Only root can raise thread priority on POSIX environment. On Linux, users
210 // who have CAP_SYS_NICE permission also can raise the thread priority, but
211 // libcap.so would be needed to check the capability.
212 return geteuid() == 0;
213 #else
214 return true;
215 #endif
216 }
217
218 class ThreadPriorityTestThread : public FunctionTestThread {
219 public:
220 ThreadPriorityTestThread() = default;
221 ~ThreadPriorityTestThread() override = default;
222
223 private:
RunTest()224 void RunTest() override {
225 // Confirm that the current thread's priority is as expected.
226 EXPECT_EQ(ThreadPriority::NORMAL,
227 PlatformThread::GetCurrentThreadPriority());
228
229 // Toggle each supported priority on the current thread and confirm it
230 // affects it.
231 const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
232 for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
233 SCOPED_TRACE(i);
234 if (!bumping_priority_allowed &&
235 kThreadPriorityTestValues[i] >
236 PlatformThread::GetCurrentThreadPriority()) {
237 continue;
238 }
239
240 // Alter and verify the current thread's priority.
241 PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
242 EXPECT_EQ(kThreadPriorityTestValues[i],
243 PlatformThread::GetCurrentThreadPriority());
244 }
245 }
246
247 DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
248 };
249
250 } // namespace
251
252 #if defined(OS_MACOSX)
253 // PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
254 #define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
255 #else
256 #define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
257 #endif
258
259 // Test changing a created thread's priority (which has different semantics on
260 // some platforms).
TEST(PlatformThreadTest,MAYBE_ThreadPriorityCurrentThread)261 TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
262 ThreadPriorityTestThread thread;
263 PlatformThreadHandle handle;
264
265 ASSERT_FALSE(thread.IsRunning());
266 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
267 thread.WaitForTerminationReady();
268 ASSERT_TRUE(thread.IsRunning());
269
270 thread.MarkForTermination();
271 PlatformThread::Join(handle);
272 ASSERT_FALSE(thread.IsRunning());
273 }
274
275 } // namespace base
276