• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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