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