OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/compiler_specific.h" | 5 #include "base/compiler_specific.h" |
| 6 #include "base/macros.h" |
| 7 #include "base/synchronization/waitable_event.h" |
6 #include "base/threading/platform_thread.h" | 8 #include "base/threading/platform_thread.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" |
7 | 10 |
8 #include "testing/gtest/include/gtest/gtest.h" | 11 #if defined(OS_WIN) |
| 12 #include <windows.h> |
| 13 #endif |
9 | 14 |
10 namespace base { | 15 namespace base { |
11 | 16 |
12 // Trivial tests that thread runs and doesn't crash on create and join --------- | 17 // Trivial tests that thread runs and doesn't crash on create and join --------- |
13 | 18 |
14 class TrivialThread : public PlatformThread::Delegate { | 19 class TrivialThread : public PlatformThread::Delegate { |
15 public: | 20 public: |
16 TrivialThread() : did_run_(false) {} | 21 TrivialThread() : did_run_(false) {} |
17 | 22 |
18 void ThreadMain() override { did_run_ = true; } | 23 void ThreadMain() override { did_run_ = true; } |
(...skipping 25 matching lines...) Expand all Loading... |
44 for (size_t n = 0; n < arraysize(thread); n++) | 49 for (size_t n = 0; n < arraysize(thread); n++) |
45 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); | 50 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); |
46 for (size_t n = 0; n < arraysize(thread); n++) | 51 for (size_t n = 0; n < arraysize(thread); n++) |
47 PlatformThread::Join(handle[n]); | 52 PlatformThread::Join(handle[n]); |
48 for (size_t n = 0; n < arraysize(thread); n++) | 53 for (size_t n = 0; n < arraysize(thread); n++) |
49 ASSERT_TRUE(thread[n].did_run()); | 54 ASSERT_TRUE(thread[n].did_run()); |
50 } | 55 } |
51 | 56 |
52 // Tests of basic thread functions --------------------------------------------- | 57 // Tests of basic thread functions --------------------------------------------- |
53 | 58 |
54 class FunctionTestThread : public TrivialThread { | 59 class FunctionTestThread : public PlatformThread::Delegate { |
55 public: | 60 public: |
56 FunctionTestThread() : thread_id_(0) {} | 61 FunctionTestThread() |
| 62 : thread_id_(kInvalidThreadId), |
| 63 thread_started_(true, false), |
| 64 terminate_thread_(true, false), |
| 65 done_(false) {} |
| 66 ~FunctionTestThread() override { |
| 67 EXPECT_TRUE(terminate_thread_.IsSignaled()) |
| 68 << "Need to mark thread for termination and join the underlying thread " |
| 69 << "before destroying a FunctionTestThread as it owns the " |
| 70 << "WaitableEvent blocking the underlying thread's main."; |
| 71 } |
57 | 72 |
| 73 // Grabs |thread_id_|, signals |thread_started_|, and then waits for |
| 74 // |terminate_thread_| to be signaled before exiting. |
58 void ThreadMain() override { | 75 void ThreadMain() override { |
59 thread_id_ = PlatformThread::CurrentId(); | 76 thread_id_ = PlatformThread::CurrentId(); |
60 PlatformThread::YieldCurrentThread(); | 77 EXPECT_NE(thread_id_, kInvalidThreadId); |
61 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
62 | 78 |
63 // Make sure that the thread ID is the same across calls. | 79 // Make sure that the thread ID is the same across calls. |
64 EXPECT_EQ(thread_id_, PlatformThread::CurrentId()); | 80 EXPECT_EQ(thread_id_, PlatformThread::CurrentId()); |
65 | 81 |
66 TrivialThread::ThreadMain(); | 82 thread_started_.Signal(); |
| 83 |
| 84 terminate_thread_.Wait(); |
| 85 |
| 86 done_ = true; |
67 } | 87 } |
68 | 88 |
69 PlatformThreadId thread_id() const { return thread_id_; } | 89 PlatformThreadId thread_id() const { |
| 90 EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown"; |
| 91 return thread_id_; |
| 92 } |
| 93 |
| 94 bool IsRunning() const { |
| 95 return thread_started_.IsSignaled() && !done_; |
| 96 } |
| 97 |
| 98 // Blocks until this thread is started. |
| 99 void WaitForThreadStart() { thread_started_.Wait(); } |
| 100 |
| 101 // Mark this thread for termination (callers must then join this thread to be |
| 102 // guaranteed of termination). |
| 103 void MarkForTermination() { terminate_thread_.Signal(); } |
70 | 104 |
71 private: | 105 private: |
72 PlatformThreadId thread_id_; | 106 PlatformThreadId thread_id_; |
73 | 107 |
| 108 mutable WaitableEvent thread_started_; |
| 109 WaitableEvent terminate_thread_; |
| 110 bool done_; |
| 111 |
74 DISALLOW_COPY_AND_ASSIGN(FunctionTestThread); | 112 DISALLOW_COPY_AND_ASSIGN(FunctionTestThread); |
75 }; | 113 }; |
76 | 114 |
77 TEST(PlatformThreadTest, Function) { | 115 TEST(PlatformThreadTest, Function) { |
78 PlatformThreadId main_thread_id = PlatformThread::CurrentId(); | 116 PlatformThreadId main_thread_id = PlatformThread::CurrentId(); |
79 | 117 |
80 FunctionTestThread thread; | 118 FunctionTestThread thread; |
81 PlatformThreadHandle handle; | 119 PlatformThreadHandle handle; |
82 | 120 |
83 ASSERT_FALSE(thread.did_run()); | 121 ASSERT_FALSE(thread.IsRunning()); |
84 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); | 122 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 123 thread.WaitForThreadStart(); |
| 124 ASSERT_TRUE(thread.IsRunning()); |
| 125 EXPECT_NE(thread.thread_id(), main_thread_id); |
| 126 |
| 127 thread.MarkForTermination(); |
85 PlatformThread::Join(handle); | 128 PlatformThread::Join(handle); |
86 ASSERT_TRUE(thread.did_run()); | 129 ASSERT_FALSE(thread.IsRunning()); |
87 EXPECT_NE(thread.thread_id(), main_thread_id); | |
88 | 130 |
89 // Make sure that the thread ID is the same across calls. | 131 // Make sure that the thread ID is the same across calls. |
90 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); | 132 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); |
91 } | 133 } |
92 | 134 |
93 TEST(PlatformThreadTest, FunctionTimesTen) { | 135 TEST(PlatformThreadTest, FunctionTimesTen) { |
94 PlatformThreadId main_thread_id = PlatformThread::CurrentId(); | 136 PlatformThreadId main_thread_id = PlatformThread::CurrentId(); |
95 | 137 |
96 FunctionTestThread thread[10]; | 138 FunctionTestThread thread[10]; |
97 PlatformThreadHandle handle[arraysize(thread)]; | 139 PlatformThreadHandle handle[arraysize(thread)]; |
98 | 140 |
99 for (size_t n = 0; n < arraysize(thread); n++) | 141 for (size_t n = 0; n < arraysize(thread); n++) |
100 ASSERT_FALSE(thread[n].did_run()); | 142 ASSERT_FALSE(thread[n].IsRunning()); |
| 143 |
101 for (size_t n = 0; n < arraysize(thread); n++) | 144 for (size_t n = 0; n < arraysize(thread); n++) |
102 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); | 145 ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); |
103 for (size_t n = 0; n < arraysize(thread); n++) | 146 for (size_t n = 0; n < arraysize(thread); n++) |
104 PlatformThread::Join(handle[n]); | 147 thread[n].WaitForThreadStart(); |
| 148 |
105 for (size_t n = 0; n < arraysize(thread); n++) { | 149 for (size_t n = 0; n < arraysize(thread); n++) { |
106 ASSERT_TRUE(thread[n].did_run()); | 150 ASSERT_TRUE(thread[n].IsRunning()); |
107 EXPECT_NE(thread[n].thread_id(), main_thread_id); | 151 EXPECT_NE(thread[n].thread_id(), main_thread_id); |
108 | 152 |
109 // Make sure no two threads get the same ID. | 153 // Make sure no two threads get the same ID. |
110 for (size_t i = 0; i < n; ++i) { | 154 for (size_t i = 0; i < n; ++i) { |
111 EXPECT_NE(thread[i].thread_id(), thread[n].thread_id()); | 155 EXPECT_NE(thread[i].thread_id(), thread[n].thread_id()); |
112 } | 156 } |
113 } | 157 } |
114 | 158 |
| 159 for (size_t n = 0; n < arraysize(thread); n++) |
| 160 thread[n].MarkForTermination(); |
| 161 for (size_t n = 0; n < arraysize(thread); n++) |
| 162 PlatformThread::Join(handle[n]); |
| 163 for (size_t n = 0; n < arraysize(thread); n++) |
| 164 ASSERT_FALSE(thread[n].IsRunning()); |
| 165 |
115 // Make sure that the thread ID is the same across calls. | 166 // Make sure that the thread ID is the same across calls. |
116 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); | 167 EXPECT_EQ(main_thread_id, PlatformThread::CurrentId()); |
117 } | 168 } |
118 | 169 |
| 170 namespace { |
| 171 |
| 172 const ThreadPriority kThreadPriorityTestValues[] = { |
| 173 // Disable non-normal priority toggling on POSIX as it appears to be broken |
| 174 // (http://crbug.com/468793). This is prefered to disabling the tests altogether |
| 175 // on POSIX as it at least provides coverage for running this code under |
| 176 // "normal" priority. |
| 177 #if !defined(OS_POSIX) |
| 178 kThreadPriority_RealtimeAudio, |
| 179 kThreadPriority_Display, |
| 180 kThreadPriority_Background, |
| 181 #endif // !defined(OS_POSIX) |
| 182 // Keep normal last to test unbackgrounding. |
| 183 kThreadPriority_Normal |
| 184 }; |
| 185 |
| 186 } // namespace |
| 187 |
| 188 // Test changing another thread's priority. |
| 189 // NOTE: This test is partially disabled on POSIX, see note above and |
| 190 // http://crbug.com/468793. |
| 191 TEST(PlatformThreadTest, ThreadPriorityOtherThread) { |
| 192 PlatformThreadHandle current_handle(PlatformThread::CurrentHandle()); |
| 193 |
| 194 // Confirm that the current thread's priority is as expected. |
| 195 EXPECT_EQ(kThreadPriority_Normal, |
| 196 PlatformThread::GetThreadPriority(current_handle)); |
| 197 |
| 198 // Create a test thread. |
| 199 FunctionTestThread thread; |
| 200 PlatformThreadHandle handle; |
| 201 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 202 thread.WaitForThreadStart(); |
| 203 EXPECT_NE(thread.thread_id(), kInvalidThreadId); |
| 204 EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId()); |
| 205 |
| 206 // New threads should get normal priority by default. |
| 207 EXPECT_EQ(kThreadPriority_Normal, PlatformThread::GetThreadPriority(handle)); |
| 208 |
| 209 // Toggle each supported priority on the test thread and confirm it only |
| 210 // affects it (and not the current thread). |
| 211 for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) { |
| 212 SCOPED_TRACE(i); |
| 213 |
| 214 // Alter and verify the test thread's priority. |
| 215 PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]); |
| 216 EXPECT_EQ(kThreadPriorityTestValues[i], |
| 217 PlatformThread::GetThreadPriority(handle)); |
| 218 |
| 219 // Make sure the current thread was otherwise unaffected. |
| 220 EXPECT_EQ(kThreadPriority_Normal, |
| 221 PlatformThread::GetThreadPriority(current_handle)); |
| 222 } |
| 223 |
| 224 thread.MarkForTermination(); |
| 225 PlatformThread::Join(handle); |
| 226 } |
| 227 |
| 228 // Test changing the current thread's priority (which has different semantics on |
| 229 // some platforms). |
| 230 // NOTE: This test is partially disabled on POSIX, see note above and |
| 231 // http://crbug.com/468793. |
| 232 TEST(PlatformThreadTest, ThreadPriorityCurrentThread) { |
| 233 PlatformThreadHandle current_handle(PlatformThread::CurrentHandle()); |
| 234 |
| 235 // Confirm that the current thread's priority is as expected. |
| 236 EXPECT_EQ(kThreadPriority_Normal, |
| 237 PlatformThread::GetThreadPriority(current_handle)); |
| 238 |
| 239 // Create a test thread for verification purposes only. |
| 240 FunctionTestThread thread; |
| 241 PlatformThreadHandle handle; |
| 242 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 243 thread.WaitForThreadStart(); |
| 244 EXPECT_NE(thread.thread_id(), kInvalidThreadId); |
| 245 EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId()); |
| 246 |
| 247 // Confirm that the new thread's priority is as expected. |
| 248 EXPECT_EQ(kThreadPriority_Normal, PlatformThread::GetThreadPriority(handle)); |
| 249 |
| 250 // Toggle each supported priority on the current thread and confirm it only |
| 251 // affects it (and not the test thread). |
| 252 for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) { |
| 253 SCOPED_TRACE(i); |
| 254 |
| 255 // Alter and verify the current thread's priority. |
| 256 PlatformThread::SetThreadPriority(current_handle, |
| 257 kThreadPriorityTestValues[i]); |
| 258 EXPECT_EQ(kThreadPriorityTestValues[i], |
| 259 PlatformThread::GetThreadPriority(current_handle)); |
| 260 |
| 261 // Make sure the test thread was otherwise unaffected. |
| 262 EXPECT_EQ(kThreadPriority_Normal, |
| 263 PlatformThread::GetThreadPriority(handle)); |
| 264 } |
| 265 |
| 266 // Restore current thread priority for follow-up tests. |
| 267 PlatformThread::SetThreadPriority(current_handle, kThreadPriority_Normal); |
| 268 |
| 269 thread.MarkForTermination(); |
| 270 PlatformThread::Join(handle); |
| 271 } |
| 272 |
119 } // namespace base | 273 } // namespace base |
OLD | NEW |