Roll src/third_party/WebKit 640e652:eec14d5 (svn 200948:200949)
[chromium-blink-merge.git] / base / threading / platform_thread_unittest.cc
blob1ac08a77ae2dea6836d60f0b8ad69104419ddd9e
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.
5 #include "base/compiler_specific.h"
6 #include "base/macros.h"
7 #include "base/synchronization/waitable_event.h"
8 #include "base/threading/platform_thread.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 #if defined(OS_POSIX)
12 #include <sys/types.h>
13 #include <unistd.h>
14 #elif defined(OS_WIN)
15 #include <windows.h>
16 #endif
18 namespace base {
20 // Trivial tests that thread runs and doesn't crash on create and join ---------
22 namespace {
24 class TrivialThread : public PlatformThread::Delegate {
25 public:
26 TrivialThread() : did_run_(false) {}
28 void ThreadMain() override { did_run_ = true; }
30 bool did_run() const { return did_run_; }
32 private:
33 bool did_run_;
35 DISALLOW_COPY_AND_ASSIGN(TrivialThread);
38 } // namespace
40 TEST(PlatformThreadTest, Trivial) {
41 TrivialThread thread;
42 PlatformThreadHandle handle;
44 ASSERT_FALSE(thread.did_run());
45 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
46 PlatformThread::Join(handle);
47 ASSERT_TRUE(thread.did_run());
50 TEST(PlatformThreadTest, TrivialTimesTen) {
51 TrivialThread thread[10];
52 PlatformThreadHandle handle[arraysize(thread)];
54 for (size_t n = 0; n < arraysize(thread); n++)
55 ASSERT_FALSE(thread[n].did_run());
56 for (size_t n = 0; n < arraysize(thread); n++)
57 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
58 for (size_t n = 0; n < arraysize(thread); n++)
59 PlatformThread::Join(handle[n]);
60 for (size_t n = 0; n < arraysize(thread); n++)
61 ASSERT_TRUE(thread[n].did_run());
64 // Tests of basic thread functions ---------------------------------------------
66 namespace {
68 class FunctionTestThread : public PlatformThread::Delegate {
69 public:
70 FunctionTestThread()
71 : thread_id_(kInvalidThreadId),
72 termination_ready_(true, false),
73 terminate_thread_(true, false),
74 done_(false) {}
75 ~FunctionTestThread() override {
76 EXPECT_TRUE(terminate_thread_.IsSignaled())
77 << "Need to mark thread for termination and join the underlying thread "
78 << "before destroying a FunctionTestThread as it owns the "
79 << "WaitableEvent blocking the underlying thread's main.";
82 // Grabs |thread_id_|, runs an optional test on that thread, signals
83 // |termination_ready_|, and then waits for |terminate_thread_| to be
84 // signaled before exiting.
85 void ThreadMain() override {
86 thread_id_ = PlatformThread::CurrentId();
87 EXPECT_NE(thread_id_, kInvalidThreadId);
89 // Make sure that the thread ID is the same across calls.
90 EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
92 // Run extra tests.
93 RunTest();
95 termination_ready_.Signal();
96 terminate_thread_.Wait();
98 done_ = true;
101 PlatformThreadId thread_id() const {
102 EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
103 return thread_id_;
106 bool IsRunning() const {
107 return termination_ready_.IsSignaled() && !done_;
110 // Blocks until this thread is started and ready to be terminated.
111 void WaitForTerminationReady() { termination_ready_.Wait(); }
113 // Marks this thread for termination (callers must then join this thread to be
114 // guaranteed of termination).
115 void MarkForTermination() { terminate_thread_.Signal(); }
117 private:
118 // Runs an optional test on the newly created thread.
119 virtual void RunTest() {}
121 PlatformThreadId thread_id_;
123 mutable WaitableEvent termination_ready_;
124 WaitableEvent terminate_thread_;
125 bool done_;
127 DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
130 } // namespace
132 TEST(PlatformThreadTest, Function) {
133 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
135 FunctionTestThread thread;
136 PlatformThreadHandle handle;
138 ASSERT_FALSE(thread.IsRunning());
139 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
140 thread.WaitForTerminationReady();
141 ASSERT_TRUE(thread.IsRunning());
142 EXPECT_NE(thread.thread_id(), main_thread_id);
144 thread.MarkForTermination();
145 PlatformThread::Join(handle);
146 ASSERT_FALSE(thread.IsRunning());
148 // Make sure that the thread ID is the same across calls.
149 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
152 TEST(PlatformThreadTest, FunctionTimesTen) {
153 PlatformThreadId main_thread_id = PlatformThread::CurrentId();
155 FunctionTestThread thread[10];
156 PlatformThreadHandle handle[arraysize(thread)];
158 for (size_t n = 0; n < arraysize(thread); n++)
159 ASSERT_FALSE(thread[n].IsRunning());
161 for (size_t n = 0; n < arraysize(thread); n++)
162 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
163 for (size_t n = 0; n < arraysize(thread); n++)
164 thread[n].WaitForTerminationReady();
166 for (size_t n = 0; n < arraysize(thread); n++) {
167 ASSERT_TRUE(thread[n].IsRunning());
168 EXPECT_NE(thread[n].thread_id(), main_thread_id);
170 // Make sure no two threads get the same ID.
171 for (size_t i = 0; i < n; ++i) {
172 EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
176 for (size_t n = 0; n < arraysize(thread); n++)
177 thread[n].MarkForTermination();
178 for (size_t n = 0; n < arraysize(thread); n++)
179 PlatformThread::Join(handle[n]);
180 for (size_t n = 0; n < arraysize(thread); n++)
181 ASSERT_FALSE(thread[n].IsRunning());
183 // Make sure that the thread ID is the same across calls.
184 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
187 namespace {
189 const ThreadPriority kThreadPriorityTestValues[] = {
190 // The order should be higher to lower to cover as much cases as possible on
191 // Linux trybots running without CAP_SYS_NICE permission.
192 #if !defined(OS_ANDROID)
193 // PlatformThread::GetCurrentThreadPriority() on Android does not support
194 // REALTIME_AUDIO case. See http://crbug.com/505474.
195 ThreadPriority::REALTIME_AUDIO,
196 #endif
197 ThreadPriority::DISPLAY,
198 // This redundant BACKGROUND priority is to test backgrounding from other
199 // priorities, and unbackgrounding.
200 ThreadPriority::BACKGROUND,
201 ThreadPriority::NORMAL,
202 ThreadPriority::BACKGROUND};
204 bool IsBumpingPriorityAllowed() {
205 #if defined(OS_POSIX)
206 // Only root can raise thread priority on POSIX environment. On Linux, users
207 // who have CAP_SYS_NICE permission also can raise the thread priority, but
208 // libcap.so would be needed to check the capability.
209 return geteuid() == 0;
210 #else
211 return true;
212 #endif
215 class ThreadPriorityTestThread : public FunctionTestThread {
216 public:
217 ThreadPriorityTestThread() = default;
218 ~ThreadPriorityTestThread() override = default;
220 private:
221 void RunTest() override {
222 // Confirm that the current thread's priority is as expected.
223 EXPECT_EQ(ThreadPriority::NORMAL,
224 PlatformThread::GetCurrentThreadPriority());
226 // Toggle each supported priority on the current thread and confirm it
227 // affects it.
228 const bool bumping_priority_allowed = IsBumpingPriorityAllowed();
229 for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
230 SCOPED_TRACE(i);
231 if (!bumping_priority_allowed &&
232 kThreadPriorityTestValues[i] >
233 PlatformThread::GetCurrentThreadPriority()) {
234 continue;
237 // Alter and verify the current thread's priority.
238 PlatformThread::SetCurrentThreadPriority(kThreadPriorityTestValues[i]);
239 EXPECT_EQ(kThreadPriorityTestValues[i],
240 PlatformThread::GetCurrentThreadPriority());
244 DISALLOW_COPY_AND_ASSIGN(ThreadPriorityTestThread);
247 } // namespace
249 #if defined(OS_MACOSX)
250 // PlatformThread::GetCurrentThreadPriority() is not implemented on OS X.
251 #define MAYBE_ThreadPriorityCurrentThread DISABLED_ThreadPriorityCurrentThread
252 #else
253 #define MAYBE_ThreadPriorityCurrentThread ThreadPriorityCurrentThread
254 #endif
256 // Test changing a created thread's priority (which has different semantics on
257 // some platforms).
258 TEST(PlatformThreadTest, MAYBE_ThreadPriorityCurrentThread) {
259 ThreadPriorityTestThread thread;
260 PlatformThreadHandle handle;
262 ASSERT_FALSE(thread.IsRunning());
263 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
264 thread.WaitForTerminationReady();
265 ASSERT_TRUE(thread.IsRunning());
267 thread.MarkForTermination();
268 PlatformThread::Join(handle);
269 ASSERT_FALSE(thread.IsRunning());
272 } // namespace base