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 21namespace base { 22 23// Trivial tests that thread runs and doesn't crash on create and join --------- 24 25namespace { 26 27class TrivialThread : public PlatformThread::Delegate { 28 public: 29 TrivialThread() : did_run_(false) {} 30 31 void ThreadMain() override { did_run_ = true; } 32 33 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 43TEST(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 53TEST(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 69namespace { 70 71class FunctionTestThread : public PlatformThread::Delegate { 72 public: 73 FunctionTestThread() 74 : thread_id_(kInvalidThreadId), 75 termination_ready_(true, false), 76 terminate_thread_(true, false), 77 done_(false) {} 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. 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 104 PlatformThreadId thread_id() const { 105 EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown"; 106 return thread_id_; 107 } 108 109 bool IsRunning() const { 110 return termination_ready_.IsSignaled() && !done_; 111 } 112 113 // Blocks until this thread is started and ready to be terminated. 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). 118 void MarkForTermination() { terminate_thread_.Signal(); } 119 120 private: 121 // Runs an optional test on the newly created thread. 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 135TEST(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 155TEST(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 190namespace { 191 192const 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 207bool 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 218class ThreadPriorityTestThread : public FunctionTestThread { 219 public: 220 ThreadPriorityTestThread() = default; 221 ~ThreadPriorityTestThread() override = default; 222 223 private: 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). 261TEST(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