• 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 <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